Skip to content

Commit ef428b2

Browse files
committed
compare plans
1 parent 2a18643 commit ef428b2

File tree

1 file changed

+61
-18
lines changed

1 file changed

+61
-18
lines changed

redisgraph/execution_plan.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
class Operation:
22
"""
3-
Operation, single operation of execution plan.
3+
Operation, single operation within execution plan.
44
"""
5+
56
def __init__(self, name, args=None):
67
"""
78
Create a new operation.
89
910
Args:
1011
name: string that represents the name of the operation
11-
args: coperation arguments
12+
args: operation arguments
1213
"""
1314
self.name = name
1415
self.args = args
@@ -21,58 +22,99 @@ def append_child(self, child):
2122
self.children.append(child)
2223
return self
2324

25+
def child_count(self):
26+
return array_len(self.children)
27+
2428
def __eq__(self, o: object) -> bool:
2529
if not isinstance(o, Operation):
2630
return False
2731

28-
if self.name != o.name or self.args != o.args or len(self.children) != len(o.children):
32+
if self.name != o.name or self.args != o.args:
2933
return False
3034

31-
for i in range(len(self.children)):
32-
if not self.children[i] == o.children[i]:
33-
return False
34-
3535
return True
3636

3737
def __str__(self) -> str:
3838
args_str = "" if self.args is None else f" | {self.args}"
3939
return f"{self.name}{args_str}"
4040

41-
4241
class ExecutionPlan:
4342
"""
4443
ExecutionPlan, collection of operations.
4544
"""
45+
4646
def __init__(self, plan):
4747
"""
4848
Create a new execution plan.
4949
5050
Args:
5151
plan: array of strings that represents the collection operations
52+
the output from GRAPH.EXPLAIN
5253
"""
5354
if not isinstance(plan, list):
54-
raise Exception("plan must be array")
55+
raise Exception("plan must be an array")
5556

5657
self.plan = plan
5758
self.structured_plan = self._operation_tree()
5859

59-
def _operation_traverse(self, op, op_f, aggregate_f, combine_f):
60-
child_res = op_f(op)
61-
if len(op.children) == 0:
62-
return child_res
63-
else:
64-
children = [self._operation_traverse(op, op_f, aggregate_f, combine_f) for op in op.children]
65-
return combine_f(child_res, aggregate_f(children))
60+
def _compare_operations(self, root_a, root_b):
61+
"""
62+
Compare execution plan operation tree
63+
64+
Return: True if operation trees are equal, False otherwise
65+
"""
66+
67+
# compare current root
68+
if root_a != root_b:
69+
return False
70+
71+
# make sure root have the same number of children
72+
if root_a.child_count() != root_b.child_count():
73+
return False
74+
75+
# recursively compare children
76+
for i in range(root_a.child_count()):
77+
if not self._compare_operations(root_a.children[i], root_b.children[i]):
78+
return False
79+
80+
return True
6681

6782
def __str__(self) -> str:
68-
def aggraget_str(str_ops):
69-
return "\n".join([" " + line for str_op in str_ops for line in str_op.splitlines()])
83+
def aggraget_str(str_children):
84+
return "\n".join([" " + line for str_child in str_children for line in str_child.splitlines()])
7085

7186
def combine_str(x, y):
7287
return f"{x}\n{y}"
88+
7389
return self._operation_traverse(self.structured_plan, str, aggraget_str, combine_str)
7490

91+
def __eq__(self, o: object) -> bool:
92+
""" Compares two execution plans
93+
94+
Return: True if the two plans are equal False otherwise
95+
"""
96+
# make sure 'o' is an execution-plan
97+
if not isinstance(o, ExecutionPlan):
98+
return False
99+
100+
# get root for both plans
101+
root_a = self.structured_plan
102+
root_b = o.structured_plan
103+
104+
# compare execution trees
105+
return self._compare_operations(root_a, root_b)
106+
107+
def _operation_traverse(self, op, op_f, aggregate_f, combine_f):
108+
# TODO: document function and its arguments
109+
child_res = op_f(op)
110+
if len(op.children) == 0:
111+
return child_res
112+
else:
113+
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))
115+
75116
def _operation_tree(self):
117+
# TODO: document!
76118
i = 0
77119
level = 0
78120
stack = []
@@ -101,3 +143,4 @@ def _operation_tree(self):
101143
else:
102144
raise Exception("corrupted plan")
103145
return stack[0]
146+

0 commit comments

Comments
 (0)