def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> Optional[Any] parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append( [ "enter", type(node).__name__, node.value if type(node).__name__ == "Name" else None, str(parent_type) if parent_type else None, str(_type) if _type else None, str(input_type) if input_type else None, ] ) # Make a query valid by adding missing selection sets. if ( type(node).__name__ == "Field" and not node.selection_set and is_composite_type(get_named_type(_type)) ): return Field( alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, selection_set=SelectionSet([Field(name=Name(value="__typename"))]), )
def test_visits_edited_node(): # type: () -> None added_field = Field(name=Name(value="__typename")) ast = parse("{ a { x } }") class TestVisitor(Visitor): def __init__(self): # type: () -> None self.did_visit_added_field = False def enter(self, node, *args): # type: (Any, *Any) -> Optional[Field] if isinstance(node, Field) and node.name.value == "a": selection_set = node.selection_set selections = [] if selection_set: selections = selection_set.selections new_selection_set = SelectionSet(selections=[added_field] + selections) return Field(name=None, selection_set=new_selection_set) if node is added_field: self.did_visit_added_field = True visitor = TestVisitor() visit(ast, visitor) assert visitor.did_visit_added_field
def _get_minimal_query_ast_from_macro_ast(macro_ast): """Get a query that should successfully compile to IR if the macro is valid.""" ast_without_macro_directives = remove_directives_from_ast(macro_ast, { directive.name for directive in DIRECTIVES_REQUIRED_IN_MACRO_EDGE_DEFINITION }) # We will add this output directive to make the ast a valid query output_directive = Directive(Name('output'), arguments=[ Argument(Name('out_name'), StringValue('dummy_output_name')) ]) # Shallow copy everything on the path to the first level selection list query_ast = copy(ast_without_macro_directives) root_level_selection = copy(get_only_selection_from_ast(query_ast, GraphQLInvalidMacroError)) first_level_selections = copy(root_level_selection.selection_set.selections) # Add an output to a new or existing __typename field existing_typename_field = None for idx, selection in enumerate(first_level_selections): if isinstance(selection, Field): if selection.name.value == '__typename': # We have a copy of the list, but the elements are references to objects # in macro_ast that we don't want to mutate. So the following copy is necessary. existing_typename_field = copy(selection) existing_typename_field.directives = copy(existing_typename_field.directives) existing_typename_field.directives.append(output_directive) first_level_selections[idx] = existing_typename_field if existing_typename_field is None: first_level_selections.insert(0, Field(Name('__typename'), directives=[output_directive])) # Propagate the changes back to the result_ast root_level_selection.selection_set = SelectionSet(first_level_selections) query_ast.selection_set = SelectionSet([root_level_selection]) return Document([query_ast])
def enter(self, node, *args): if isinstance(node, Field) and node.name.value == 'a': selection_set = node.selection_set selections = [] if selection_set: selections = selection_set.selections new_selection_set = SelectionSet(selections=[added_field] + selections) return Field(name=None, selection_set=new_selection_set) if node is added_field: self.did_visit_added_field = True
def _get_property_field(existing_field, field_name, directives_from_edge): """Return a Field object with field_name, sharing directives with any such existing field. Any valid directives in directives_on_edge will be transferred over to the new field. If there is an existing Field in selection with field_name, the returned new Field will also contain all directives of the existing field with that name. Args: existing_field: Field or None. If it's not None, it is a field with field_name. The directives of this field will carry output to the output field field_name: str, the name of the output field directives_from_edge: List[Directive], the directives of a vertex field. The output field will contain all @filter and any @optional directives from this list Returns: Field object, with field_name as its name, containing directives from any field in the input selections with the same name and directives from the input list of directives """ new_field = Field( name=Name(value=field_name), directives=[], ) # Transfer directives from existing field of the same name if existing_field is not None: # Existing field, add all its directives directives_from_existing_field = existing_field.directives if directives_from_existing_field is not None: new_field.directives.extend(directives_from_existing_field) # Transfer directives from edge if directives_from_edge is not None: for directive in directives_from_edge: if directive.name.value == OutputDirective.name: # output illegal on vertex field raise GraphQLValidationError( u'Directive "{}" is not allowed on a vertex field, as @output directives ' u'can only exist on property fields.'.format(directive)) elif directive.name.value == OptionalDirective.name: if try_get_ast_by_name_and_type(new_field.directives, OptionalDirective.name, Directive) is None: # New optional directive new_field.directives.append(directive) elif directive.name.value == FilterDirective.name: new_field.directives.append(directive) else: raise AssertionError( u'Unreachable code reached. Directive "{}" is of an unsupported type, and ' u'was not caught in a prior validation step.'.format( directive)) return new_field
def _get_query_document(root_vertex_field_name, root_selections): """Return a Document representing a query with the specified name and selections.""" return Document(definitions=[ OperationDefinition(operation='query', selection_set=SelectionSet(selections=[ Field( name=Name(value=root_vertex_field_name), selection_set=SelectionSet( selections=root_selections, ), directives=[], ) ])) ])
def enter(self, node, key, parent, *args): parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append([ 'enter', type(node).__name__, node.value if type(node).__name__ == "Name" else None, str(parent_type) if parent_type else None, str(_type) if _type else None, str(input_type) if input_type else None ]) # Make a query valid by adding missing selection sets. if type( node ).__name__ == "Field" and not node.selection_set and is_composite_type( get_named_type(_type)): return Field(alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, selection_set=SelectionSet( [Field(name=Name(value='__typename'))]))
def test_visits_edited_node(): added_field = Field(name=Name(value='__typename')) ast = parse('{ a { x } }') class TestVisitor(Visitor): def __init__(self): self.did_visit_added_field = False def enter(self, node, *args): if isinstance(node, Field) and node.name.value == 'a': selection_set = node.selection_set selections = [] if selection_set: selections = selection_set.selections new_selection_set = SelectionSet(selections=[added_field] + selections) return Field(name=None, selection_set=new_selection_set) if node is added_field: self.did_visit_added_field = True visitor = TestVisitor() visit(ast, visitor) assert visitor.did_visit_added_field
def test_prints_minimal_ast(): # type: () -> None ast = Field(name=Name(loc=None, value="foo")) assert print_ast(ast) == "foo"