Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Simplify validator + [Validation] Remove visitFragmentSpreads
  • Loading branch information
syrusakbary committed Apr 13, 2016
commit 6cbf0b2bc11fc7961d8b59f213d17cf541ef0b89
4 changes: 2 additions & 2 deletions graphql/core/validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def validate(schema, ast, rules=specified_rules):

def visit_using_rules(schema, type_info, ast, rules):
context = ValidationContext(schema, ast, type_info)
errors = []
rules = [rule(context) for rule in rules]
visit(ast, ValidationVisitor(rules, context, type_info, errors))
for instance in rules:
visit(ast, ValidationVisitor(instance, context, type_info))
return context.get_errors()
95 changes: 9 additions & 86 deletions graphql/core/validation/visitor.py
Original file line number Diff line number Diff line change
@@ -1,101 +1,24 @@
from ..error import GraphQLError
from ..language.ast import FragmentDefinition, FragmentSpread
from ..language.visitor import Visitor, visit
from ..language.visitor import Visitor


class ValidationVisitor(Visitor):
__slots__ = 'context', 'rules', 'total_rules', 'type_info', 'errors', 'ignore_children'
__slots__ = 'context', 'instance', 'type_info'

def __init__(self, rules, context, type_info, errors):
def __init__(self, instance, context, type_info):
self.context = context
self.rules = rules
self.total_rules = len(rules)
self.instance = instance
self.type_info = type_info
self.errors = errors
self.ignore_children = {}

def enter(self, node, key, parent, path, ancestors):
self.type_info.enter(node)
to_ignore = None
rules_wanting_to_visit_fragment = None

skipped = 0
for rule in self.rules:
if rule in self.ignore_children:
skipped += 1
continue

visit_spread_fragments = getattr(rule, 'visit_spread_fragments', False)

if isinstance(node, FragmentDefinition) and key and visit_spread_fragments:
if to_ignore is None:
to_ignore = []

to_ignore.append(rule)
continue

result = rule.enter(node, key, parent, path, ancestors)

if result and is_error(result):
append(self.errors, result)
result = False

if result is None and visit_spread_fragments and isinstance(node, FragmentSpread):
if rules_wanting_to_visit_fragment is None:
rules_wanting_to_visit_fragment = []

rules_wanting_to_visit_fragment.append(rule)

if result is False:
if to_ignore is None:
to_ignore = []

to_ignore.append(rule)

if rules_wanting_to_visit_fragment:
fragment = self.context.get_fragment(node.name.value)

if fragment:
sub_visitor = ValidationVisitor(rules_wanting_to_visit_fragment, self.context, self.type_info,
self.errors)
visit(fragment, sub_visitor)

should_skip = (len(to_ignore) if to_ignore else 0 + skipped) == self.total_rules

if should_skip:
result = self.instance.enter(node, key, parent, path, ancestors)
if result is False:
self.type_info.leave(node)

elif to_ignore:
for rule in to_ignore:
self.ignore_children[rule] = node

if should_skip:
return False
return result

def leave(self, node, key, parent, path, ancestors):
for rule in self.rules:
if rule in self.ignore_children:
if self.ignore_children[rule] is node:
del self.ignore_children[rule]

continue

result = rule.leave(node, key, parent, path, ancestors)

if result and is_error(result):
append(self.errors, result)
result = self.instance.leave(node, key, parent, path, ancestors)

self.type_info.leave(node)


def is_error(value):
if isinstance(value, list):
return all(isinstance(item, GraphQLError) for item in value)
return isinstance(value, GraphQLError)


def append(arr, items):
if isinstance(items, list):
arr.extend(items)
else:
arr.append(items)
return result