def factory(nodes: SelectionNodes) -> graphql.InlineFragmentNode: return graphql.InlineFragmentNode( type_condition=graphql.NamedTypeNode( name=graphql.NameNode(value=type_name), ), selection_set=graphql.SelectionSetNode(kind="selection_set", selections=nodes), )
def factory(tup: FieldNodeInput) -> graphql.FieldNode: return graphql.FieldNode( name=graphql.NameNode(value=name), arguments=tup[0], selection_set=graphql.SelectionSetNode( kind="selection_set", selections=add_selection_aliases(tup[1])), )
def object_field_nodes( name: str, field: graphql.GraphQLInputField ) -> st.SearchStrategy[graphql.ObjectFieldNode]: return st.builds( partial(graphql.ObjectFieldNode, name=graphql.NameNode(value=name)), # type: ignore value=value_nodes(field.type), )
def list_of_arguments( **kwargs: graphql.GraphQLArgument ) -> st.SearchStrategy[List[graphql.ArgumentNode]]: """Generate a list `graphql.ArgumentNode` for a field.""" return st.tuples(*( st.builds(partial(graphql.ArgumentNode, name=graphql.NameNode(value=name)), value=argument_values(argument)) # type: ignore for name, argument in kwargs.items())).map(finalize_arguments)
def add_alias(frag: graphql.InlineFragmentNode) -> graphql.InlineFragmentNode: # Add an alias for all fields that have the same name with already selected ones but a different type fragment_type = type_map[frag.type_condition.name.value] for selected in frag.selection_set.selections: field_name = selected.name.value if field_name in seen: field_type = fragment_type.fields[field_name].type if not is_equal_type(seen[field_name], field_type): selected.alias = graphql.NameNode(value=f"{field_name}_{make_type_name(field_type)}") return frag
def field_nodes( name: str, field: graphql.GraphQLField) -> st.SearchStrategy[graphql.FieldNode]: """Generate a single field node with optional children.""" return st.builds( partial(graphql.FieldNode, name=graphql.NameNode(value=name)), # type: ignore arguments=list_of_arguments(**field.args), selection_set=st.builds(make_selection_set_node, selections=fields_for_type(field)), )
def maybe_add_alias(field_node: graphql.FieldNode, arguments: List[graphql.ArgumentNode], seen: Dict[Tuple[str, str], List]) -> None: for argument in arguments: key = (field_node.name.value, argument.name.value) value = argument.value if key in seen: # Simply add an alias, the values could be the same, so it not technically necessary, but this is safe # and simpler, but a bit reduces the possible input variety field_node.alias = graphql.NameNode( value=f"{field_node.name.value}_{len(seen[key])}") seen[key].append(value) else: seen[key] = [value]
def inner(draw: Any) -> List[graphql.ArgumentNode]: args = [] for name, argument in arguments.items(): default = argument.ast_node.default_value if argument.ast_node is not None else None try: argument_strategy = self.values(argument.type, default=default) except InvalidArgument: if not isinstance(argument.type, graphql.GraphQLNonNull): # If the type is nullable, then either generate `null` or skip it completely if draw(st.booleans()): args.append(graphql.ArgumentNode(name=graphql.NameNode(value=name), value=nodes.Null)) continue raise args.append(draw(argument_strategy.map(factories.argument(name)))) return args
def type_to_ast(graphql_type): """ https://github.com/apollographql/graphql-tools/blob/0046a0e3bf2a120a59e4f4e392d4ddc3728e4f3c/src/transforms/AddArgumentsAsVariables.ts#L171 """ if isinstance(graphql_type, graphql.GraphQLNonNull): inner_type = type_to_ast(graphql_type.of_type) if inner_type.kind in ("list_type", "named_type"): return graphql.NonNullTypeNode(type=inner_type) else: raise ValueError("Incorrect inner non-null type.") elif isinstance(graphql_type, graphql.GraphQLList): return graphql.ListTypeNode(type=type_to_ast(graphql_type.of_type)) else: return graphql.NamedTypeNode(name=graphql.NameNode( value=str(graphql_type)))
def create_document( target_field: str, target_operation: str, original_selections: List[graphql.SelectionNode], fragments: List[graphql.FragmentDefinitionNode], variables: List[graphql.VariableDefinitionNode], operation_name: graphql.NameNode, ) -> graphql.DocumentNode: """ https://github.com/apollographql/graphql-tools/blob/d3cbefc6b8a432c5b22f1ce25e56757ef03f4227/src/stitching/delegateToSchema.ts#L139 """ selections: List[graphql.SelectionNode] = [] args: List[graphql.ArgumentNode] = [] for field in original_selections: selections.extend(getattr(field.selection_set, "selections", [])) args.extend(field.arguments or []) if selections: selection_set = graphql.SelectionSetNode(selections=selections) else: selection_set = None root_field = graphql.FieldNode( alias=None, arguments=args, selection_set=selection_set, name=graphql.NameNode(value=target_field), ) root_selection_set = graphql.SelectionSetNode(selections=[root_field]) operation_definition = graphql.OperationDefinitionNode( operation=target_operation, variable_definitions=variables, selection_set=root_selection_set, name=operation_name, ) return graphql.DocumentNode(definitions=[operation_definition, *fragments])
def add_variables_to_root_field(schema: graphql.GraphQLSchema, document: graphql.DocumentNode, args: Dict[str, Any]) -> GraphQLRequest: """ https://github.com/apollographql/graphql-tools/blob/0046a0e3bf2a120a59e4f4e392d4ddc3728e4f3c/src/transforms/AddArgumentsAsVariables.ts#L47 """ operations = [ d for d in document.definitions if d.kind == "operation_definition" ] fragments = [ d for d in document.definitions if d.kind == "fragment_definition" ] variable_names = {} for operation in operations: existing_variables = set(v.variable.name.value for v in operation.variable_definitions) variable_counter = 0 variables = {} def generate_variable_name(arg_name: str) -> str: nonlocal variable_counter variable_name = f"_v{variable_counter}_{arg_name}" while variable_name in existing_variables: variable_counter += 1 variable_name = f"_v{variable_counter}_{arg_name}" return variable_name if operation.operation == operation.operation.SUBSCRIPTION: op_type = schema.subscription_type elif operation.operation == operation.operation.MUTATION: op_type = schema.mutation_type elif operation.operation == operation.operation.QUERY: op_type = schema.query_type else: raise ValueError("Unexpected operation.") if not op_type: continue new_selection_set = [] for selection in operation.selection_set.selections: if selection.kind == "field": new_args = {arg.name.value: arg for arg in selection.arguments} name = selection.name.value field = op_type.fields[name] for argument_name, argument in field.args.items(): if argument_name in args: variable_name = generate_variable_name(argument_name) variable_names[argument_name] = variable_name new_args[argument_name] = graphql.ArgumentNode( name=graphql.NameNode(value=argument_name), value=graphql.VariableNode(name=graphql.NameNode( value=variable_name)), ) existing_variables.add(variable_name) variables[ variable_name] = graphql.VariableDefinitionNode( variable=graphql.VariableNode( name=graphql.NameNode( value=variable_name)), type=type_to_ast(graphql_type=argument.type), ) selection.arguments = list(new_args.values()) new_selection_set.append(selection) operation.variable_definitions.extend(variables.values()) operation.selection_set = graphql.SelectionSetNode( selections=new_selection_set) new_variables = { variable_names[name]: args[name] for name in variable_names } new_document = graphql.DocumentNode(definitions=operations + fragments) return GraphQLRequest(document=document, variables=new_variables)
def factory(value: graphql.ValueNode) -> graphql.ObjectFieldNode: return graphql.ObjectFieldNode(name=graphql.NameNode(value=name), value=value)
def factory(value: graphql.ValueNode) -> graphql.ArgumentNode: return graphql.ArgumentNode(name=graphql.NameNode(value=name), value=value)