def args_selection_search(self, selection_set, variables, parent_type, arg_name, arg_value): """Recursively search through feild/fragment selection set fields.""" for field in selection_set.selections: if isinstance(field, ast.FragmentSpread): if field.name.value in self.visited_fragments: continue frag_def = self.fragment_defs[field.name.value] frag_type = type_from_ast(self.schema, frag_def.type_condition) if self.args_selection_search(frag_def.selection_set, variables, frag_type, arg_name, arg_value): return True self.visited_fragments.add(frag_def.name) continue field_def = get_field_def(self.schema, parent_type, field.name.value) if field_def is None: continue arg_vals = get_argument_values(field_def.args, field.arguments, variables) if arg_vals.get(arg_name) == arg_value: return True if field.selection_set is None: continue if self.args_selection_search(field.selection_set, variables, get_named_type(field_def.type), arg_name, arg_value): return True return False
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)