示例#1
0
    def parse(
        self,
        query: str,
        full_fragments: str = "",
        should_validate: bool = True,
        is_fragment: bool = False,
    ) -> ParsedQuery:
        query_document_ast = parse("".join([full_fragments, query]))
        document_ast = parse(query)
        if not is_fragment:
            operation = get_operation_ast(document_ast)
            if not operation.name:
                raise AnonymousQueryError()

        if should_validate:
            errors = validate(
                self.schema,
                query_document_ast,
                [rule for rule in specified_rules if rule is not NoUnusedFragmentsRule],
            )
            if errors:
                raise InvalidQueryError(errors)

        type_info = TypeInfo(self.schema)
        visitor = FieldToTypeMatcherVisitor(self.schema, type_info, query)
        visit(document_ast, TypeInfoVisitor(type_info, visitor))
        result = visitor.parsed
        return result
示例#2
0
def get_input_type_from_query(query: str) -> Optional[str]:
    '''
    Given a GraphQL query for a DjangoFormMutation, return the input type, e.g.:

        >>> get_input_type_from_query(
        ...     'mutation FooMutation($input: BarInput!) { foo(input: $input) }')
        'BarInput'

    If the input type cannot be found, return None.
    '''

    try:
        ast = parse(query)
    except GraphQLSyntaxError:
        return None

    class InputTypeVisitor(Visitor):
        in_input_definition: bool = False
        input_type: Optional[str] = None

        def enter(self, node, *args):
            if isinstance(node, VariableDefinition) and node.variable.name.value == 'input':
                self.in_input_definition = True
            elif isinstance(node, NamedType) and self.in_input_definition:
                self.input_type = node.name.value

        def leave(self, node, *args):
            if isinstance(node, VariableDefinition) and node.variable.name.value == 'input':
                self.in_input_definition = False

    visitor = InputTypeVisitor()
    visit(ast, visitor)

    return visitor.input_type
示例#3
0
    def __init__(
        self,
        schema: GraphQLSchema,
        operation: OperationDefinitionNode,
        fragments: FragmentMap,
        auto_fragmentization: bool,
    ):
        self.internal_fragments = {}
        self.internal_fragment_count = 0

        self.schema = schema
        self.operation = operation
        self.fragments = fragments
        self.auto_fragmentization = auto_fragmentization

        variable_definitions = {}

        class VariableDefinitionVisitor(Visitor):
            # noinspection PyMethodMayBeStatic
            def enter_variable_definition(self, definition: VariableDefinitionNode, *_) -> None:
                variable_definitions[definition.variable.name.value] = definition

        self.variable_definitions = variable_definitions

        visit(operation, VariableDefinitionVisitor())
示例#4
0
 def _calculate_cost(ast_document, max_complexity=100) -> int:
     context = ValidationContext(schema=post_schema,
                                 ast=ast_document,
                                 type_info=TypeInfo(post_schema),
                                 on_error=on_error_stub)
     visitor = CostAnalysisVisitor(context=context,
                                   max_complexity=max_complexity)
     visit(ast_document, visitor)
     return visitor.total_complexity
示例#5
0
def parse_result_recursive(
    schema: GraphQLSchema,
    document: DocumentNode,
    node: Node,
    result: Optional[Dict[str, Any]],
    initial_type: Optional[GraphQLType] = None,
    inside_list_level: int = 0,
    visit_fragment: bool = False,
    operation_name: Optional[str] = None,
) -> Any:

    if result is None:
        return None

    type_info = TypeInfo(schema, initial_type=initial_type)

    visited = visit(
        node,
        TypeInfoVisitor(
            type_info,
            ParseResultVisitor(
                schema,
                document,
                node,
                result,
                type_info=type_info,
                inside_list_level=inside_list_level,
                visit_fragment=visit_fragment,
                operation_name=operation_name,
            ),
        ),
        visitor_keys=RESULT_DOCUMENT_KEYS,
    )

    return visited
示例#6
0
    def parse(self, query: str, should_validate: bool = True) -> ParsedQuery:
        document_ast = parse(query)
        operation = get_operation_ast(document_ast)

        if not operation.name:
            raise AnonymousQueryError()

        if should_validate:
            errors = validate(self.schema, document_ast)
            if errors:
                raise InvalidQueryError(errors)

        type_info = TypeInfo(self.schema)
        visitor = FieldToTypeMatcherVisitor(self.schema, type_info, query)
        visit(document_ast, TypeInfoVisitor(type_info, visitor))
        result = visitor.parsed
        return result
示例#7
0
    def parse(self, query: str, should_validate: bool = True) -> ParsedQuery:
        document_ast = parse(query)
        operation = get_operation_ast(document_ast)

        if not operation.name:
            raise AnonymousQueryError()

        if should_validate:
            errors = validate(self.schema, document_ast)
            if errors:
                raise InvalidQueryError(errors)

        type_info = TypeInfo(self.schema)
        visitor = FieldToTypeMatcherVisitor(self.schema, type_info, query)
        visit(document_ast, TypeInfoVisitor(type_info, visitor))
        result = visitor.parsed
        return result
示例#8
0
def validate_depth(schema: GraphQLSchema, document: DocumentNode,
                   context_value: Any, errors: List[GraphQLError]):
    def on_error(error: GraphQLError) -> None:
        errors.append(error)
        raise ValidationAbortedError

    depth_analysis = context_value.get("depth_analysis")

    if depth_analysis:
        max_depth = depth_analysis.get("max_depth", 10)
        context = ValidationContext(schema=schema,
                                    ast=document,
                                    type_info=TypeInfo(schema),
                                    on_error=on_error)

        visit(document,
              DepthAnalysisVisitor(context=context, max_depth=max_depth))
示例#9
0
def validate_cost(schema: GraphQLSchema, document: DocumentNode,
                  context_value: Any, errors: List[GraphQLError]):
    def on_error(error: GraphQLError) -> None:
        errors.append(error)
        raise ValidationAbortedError

    cost_analysis = context_value.get("cost_analysis")

    if cost_analysis:
        max_complexity = cost_analysis.get("max_complexity", 500)
        context = ValidationContext(schema=schema,
                                    ast=document,
                                    type_info=TypeInfo(schema),
                                    on_error=on_error)

        visit(
            document,
            CostAnalysisVisitor(context=context,
                                max_complexity=max_complexity))

    return []
示例#10
0
    def get_variable_usages(
        self, selection_set: SelectionSetNode, fragments: set[FragmentDefinitionNode]
    ) -> VariableUsages:
        usages: dict[str, VariableDefinitionNode] = {}

        # Construct a document of the selection set and fragment definitions so we
        # can visit them, adding all variable usages to the `usages` object.
        definitions: list[DefinitionNode] = [
            OperationDefinitionNode(selection_set=selection_set, operation=OperationType.QUERY)
        ]
        definitions.extend(fragments)
        document = DocumentNode(definitions=definitions)

        this = self

        class VariableVisitor(Visitor):
            # noinspection PyMethodMayBeStatic
            def enter_variable(self, node: VariableNode):
                usages[node.name.value] = this.variable_definitions[node.name.value]

        visit(document, VariableVisitor())

        return usages
def _split_query_one_level(
    query_node: SubQueryNode,
    merged_schema_descriptor: MergedSchemaDescriptor,
    edge_to_stitch_fields: Dict[Tuple[str, str], Tuple[str, str]],
    name_assigner: IntermediateOutNameAssigner,
) -> None:
    """Split the query node, creating children out of all branches across cross schema edges.

    The input query_node will be modified. Its query_ast will be replaced by a new AST with
    branches leading out of cross schema edges removed, and new property fields and @output
    directives added as necessary. Its child_query_connections will be modified by tacking
    on SubQueryNodes created from these cut-off branches.

    Args:
        query_node: Query to be split into its child components. Its query_ast
                    will be replaced (but the original AST will not be modified) and its
                    child_query_connections will be modified.
        merged_schema_descriptor: The schema that the query AST contained in the input
                                  query_node targets.
        edge_to_stitch_fields: Mapping (type name, vertex field name) to
                               (source field name, sink field name) used in the @stitch directive
                               for each cross schema edge.
        name_assigner: Object used to generate and keep track of names of newly created
                       @output directive.

    Raises:
        - GraphQLValidationError if the query AST contained in the input query_node is invalid,
          for example, having an @output directive on a cross schema edge
        - SchemaStructureError if the merged_schema_descriptor provided appears to be invalid
          or inconsistent
    """
    type_info = TypeInfo(merged_schema_descriptor.schema)

    operation_definition = get_only_query_definition(query_node.query_ast,
                                                     GraphQLValidationError)
    if not isinstance(operation_definition, OperationDefinitionNode):
        raise AssertionError(
            f"Expected operation_definition to be an OperationDefinitionNode, but it was of"
            f"type {type(operation_definition)}. This should be impossible.")

    type_info.enter(operation_definition)
    new_operation_definition = _split_query_ast_one_level_recursive(
        query_node, operation_definition, type_info, edge_to_stitch_fields,
        name_assigner)
    type_info.leave(operation_definition)

    if new_operation_definition is not operation_definition:
        query_node.query_ast = DocumentNode(
            definitions=[new_operation_definition])

    # Check resulting AST is valid
    validation_errors = validate(merged_schema_descriptor.schema,
                                 query_node.query_ast)
    if len(validation_errors) > 0:
        raise AssertionError(
            'The resulting split query "{}" is invalid, with the following error messages: {}'
            "".format(query_node.query_ast, validation_errors))

    # Set schema id, check for consistency
    visitor = TypeInfoVisitor(
        type_info,
        SchemaIdSetterVisitor(type_info, query_node,
                              merged_schema_descriptor.type_name_to_schema_id),
    )
    visit(query_node.query_ast, visitor)

    if query_node.schema_id is None:
        raise AssertionError(
            'Unreachable code reached. The schema id of query piece "{}" has not been '
            "determined.".format(query_node.query_ast))
示例#12
0
文件: debug.py 项目: gqlmod/gqlmod
def debug_ast(node):
    graphql.visit(node, DebugVisitor())