Skip to content

Commit 5cc0b18

Browse files
committed
Support breaking in parallel visitor
Related GraphQL-js commit: graphql/graphql-js@b2bdae0
1 parent f1febcf commit 5cc0b18

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

graphql/core/language/visitor.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,15 @@ def enter(self, node, key, parent, path, ancestors):
177177
result = visitor.enter(node, key, parent, path, ancestors)
178178
if result is False:
179179
self.skipping[i] = node
180+
elif result is BREAK:
181+
self.skipping[i] = BREAK
180182

181183
def leave(self, node, key, parent, path, ancestors):
182184
for i, visitor in enumerate(self.visitors):
183185
if not self.skipping[i]:
184-
visitor.leave(node, key, parent, path, ancestors)
186+
result = visitor.leave(node, key, parent, path, ancestors)
187+
if result is BREAK:
188+
self.skipping[i] = BREAK
185189
elif self.skipping[i] == node:
186190
self.skipping[i] = None
187191

tests/core_language/test_visitor.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from graphql.core.language.ast import Field, Name, SelectionSet
22
from graphql.core.language.parser import parse
3-
from graphql.core.language.visitor import BREAK, REMOVE, Visitor, visit, ParallelVisitor
3+
from graphql.core.language.visitor import (
4+
BREAK, REMOVE, Visitor, visit, ParallelVisitor)
45

56
from .fixtures import KITCHEN_SINK
67

@@ -578,3 +579,98 @@ def leave(self, node, key, parent, *args):
578579
['no-a', 'leave', 'Document', None],
579580
['no-b', 'leave', 'Document', None],
580581
]
582+
583+
584+
def test_visits_in_pararell_allows_early_exit_while_visiting():
585+
visited = []
586+
ast = parse('{ a, b { x }, c }')
587+
588+
class TestVisitor(Visitor):
589+
590+
def enter(self, node, key, parent, *args):
591+
visited.append(
592+
['enter', type(node).__name__, getattr(node, 'value', None)])
593+
594+
def leave(self, node, key, parent, *args):
595+
visited.append(
596+
['leave', type(node).__name__, getattr(node, 'value', None)])
597+
if type(node).__name__ == 'Name' and node.value == 'x':
598+
return BREAK
599+
600+
visit(ast, ParallelVisitor([TestVisitor()]))
601+
assert visited == [
602+
['enter', 'Document', None],
603+
['enter', 'OperationDefinition', None],
604+
['enter', 'SelectionSet', None],
605+
['enter', 'Field', None],
606+
['enter', 'Name', 'a'],
607+
['leave', 'Name', 'a'],
608+
['leave', 'Field', None],
609+
['enter', 'Field', None],
610+
['enter', 'Name', 'b'],
611+
['leave', 'Name', 'b'],
612+
['enter', 'SelectionSet', None],
613+
['enter', 'Field', None],
614+
['enter', 'Name', 'x'],
615+
['leave', 'Name', 'x']
616+
]
617+
618+
619+
def test_visits_in_pararell_allows_early_exit_from_different_points():
620+
visited = []
621+
ast = parse('{ a { y }, b { x } }')
622+
623+
class TestVisitor(Visitor):
624+
625+
def __init__(self, name):
626+
self.name = name
627+
628+
def enter(self, node, key, parent, *args):
629+
visited.append(["break-{}".format(self.name), 'enter',
630+
type(node).__name__, getattr(node, 'value', None)])
631+
632+
def leave(self, node, key, parent, *args):
633+
visited.append(["break-{}".format(self.name), 'leave',
634+
type(node).__name__, getattr(node, 'value', None)])
635+
if type(node).__name__ == 'Field' and node.name.value == self.name:
636+
return BREAK
637+
638+
visit(ast, ParallelVisitor([TestVisitor('a'), TestVisitor('b')]))
639+
assert visited == [
640+
['break-a', 'enter', 'Document', None],
641+
['break-b', 'enter', 'Document', None],
642+
['break-a', 'enter', 'OperationDefinition', None],
643+
['break-b', 'enter', 'OperationDefinition', None],
644+
['break-a', 'enter', 'SelectionSet', None],
645+
['break-b', 'enter', 'SelectionSet', None],
646+
['break-a', 'enter', 'Field', None],
647+
['break-b', 'enter', 'Field', None],
648+
['break-a', 'enter', 'Name', 'a'],
649+
['break-b', 'enter', 'Name', 'a'],
650+
['break-a', 'leave', 'Name', 'a'],
651+
['break-b', 'leave', 'Name', 'a'],
652+
['break-a', 'enter', 'SelectionSet', None],
653+
['break-b', 'enter', 'SelectionSet', None],
654+
['break-a', 'enter', 'Field', None],
655+
['break-b', 'enter', 'Field', None],
656+
['break-a', 'enter', 'Name', 'y'],
657+
['break-b', 'enter', 'Name', 'y'],
658+
['break-a', 'leave', 'Name', 'y'],
659+
['break-b', 'leave', 'Name', 'y'],
660+
['break-a', 'leave', 'Field', None],
661+
['break-b', 'leave', 'Field', None],
662+
['break-a', 'leave', 'SelectionSet', None],
663+
['break-b', 'leave', 'SelectionSet', None],
664+
['break-a', 'leave', 'Field', None],
665+
['break-b', 'leave', 'Field', None],
666+
['break-b', 'enter', 'Field', None],
667+
['break-b', 'enter', 'Name', 'b'],
668+
['break-b', 'leave', 'Name', 'b'],
669+
['break-b', 'enter', 'SelectionSet', None],
670+
['break-b', 'enter', 'Field', None],
671+
['break-b', 'enter', 'Name', 'x'],
672+
['break-b', 'leave', 'Name', 'x'],
673+
['break-b', 'leave', 'Field', None],
674+
['break-b', 'leave', 'SelectionSet', None],
675+
['break-b', 'leave', 'Field', None]
676+
]

0 commit comments

Comments
 (0)