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)