Esempio n. 1
0
    def __init__(self, schema, document_ast, variable_values):
        self.schema = schema
        self.operation_defs = {}
        self.fragment_defs = {}
        self.visited_fragments = set()

        for defn in document_ast.definitions:
            if isinstance(defn, ast.OperationDefinition):
                root_type = get_operation_root_type(schema, defn)
                definition_variables = defn.variable_definitions or []
                if definition_variables:
                    def_var_names = {
                        v.variable.name.value
                        for v in definition_variables
                    }
                    var_names_diff = def_var_names.difference(
                        {k
                         for k in variable_values if k in def_var_names})
                    # check if we are missing some of the definition variables
                    if var_names_diff:
                        msg = (f'Please check your query variables. The '
                               f'following variables are missing: '
                               f'[{", ".join(var_names_diff)}]')
                        raise ValueError(msg)
                self.operation_defs[getattr(defn.name, 'value', root_type)] = {
                    'definition':
                    defn,
                    'parent_type':
                    root_type,
                    'variables':
                    get_variable_values(schema, definition_variables,
                                        variable_values),
                }
            elif isinstance(defn, ast.FragmentDefinition):
                self.fragment_defs[defn.name.value] = defn
def resolve_prefetch(
        exe_context,  # type: ExecutionContext
        operation,  # type: OperationDefinition
        root_type=None,  # type: Any
        type_=None,
        path=None,
        selection_set=None,  # type: Optional[SelectionSet]
        action_id=None):
    if path is None:
        path = []
    if type_ is None:
        type_ = get_operation_root_type(exe_context.schema, operation)
    if isinstance(type_, GraphQLList):
        type_ = type_.of_type
    if root_type is None:
        root_type = type_.graphene_type
    if selection_set is None:
        selection_set = operation.selection_set
    fields = collect_fields(exe_context, type_, selection_set,
                            DefaultOrderedDict(list), set())
    try:
        prefetch_fn = getattr(type_.graphene_type, "prefetch_fn")
    except AttributeError:
        prefetch_fn = None
    for response_name, field_asts in fields.items():
        # todo: 这里可能有bug
        field_ast = field_asts[0]
        field_name = field_ast.name.value
        try:
            field_def = get_field_def(exe_context.schema, type_, field_name)
        except:
            field_def = None
        path_name = SKIP
        if prefetch_fn:
            try:
                # 在 prefetch_fn 中进行类似于select_related prefetch_related等操作
                # 告诉orm应该加载关系
                # 返回的东西会被拼凑到path里面,如果返回SKIP,那么不会拼路径,如果不返回,那么字段名将拼凑到路径中
                new_action_id = action_id

                def set_action_id(x):
                    nonlocal new_action_id
                    new_action_id = x

                def add_prefetch_info(x):
                    exe_context.context_value["prefetch"][action_id].append(x)

                path_name = prefetch_fn(action_id=action_id,
                                        prefetch_name=field_name,
                                        prefetch_field_def=field_def,
                                        path=path,
                                        add_prefetch_info=add_prefetch_info,
                                        set_action_id=set_action_id)
            except:
                traceback.print_exc()
        if field_def and field_ast.selection_set:
            if path_name == SKIP:
                new_path = path
            else:
                new_path = path + [path_name]
            resolve_prefetch(exe_context, operation, root_type, field_def.type,
                             new_path, field_ast.selection_set, new_action_id)