class GraphQL::Execution::Runner
Attributes
Public Class Methods
Source
# File lib/graphql/execution/runner.rb, line 6 def initialize(multiplex) @multiplex = multiplex @schema = multiplex.schema @runtime_type_at = {}.compare_by_identity @static_type_at = {}.compare_by_identity @finalizers = nil @selected_operation = nil @dataloader = multiplex.context[:dataloader] ||= @schema.dataloader_class.new @resolves_lazies = @schema.resolves_lazies? @input_values = Hash.new do |h, query| h[query] = InputValues.new(query, self) end.compare_by_identity @runtime_directives = nil #: Hash[String, singleton(GraphQL::Schema::Directive)]? @schema.directives.each do |name, dir_class| if dir_class.runtime? && name != "include" && name != "skip" @runtime_directives ||= {} @runtime_directives[dir_class.graphql_name] = dir_class end end if @runtime_directives.nil? @uses_runtime_directives = false @runtime_directives = EmptyObjects::EMPTY_HASH else @uses_runtime_directives = true end @lazy_cache = resolves_lazies ? {}.compare_by_identity : nil @authorizes_cache = Hash.new do |h, query_context| h[query_context] = {}.compare_by_identity end.compare_by_identity end
Public Instance Methods
# File lib/graphql/execution/runner.rb, line 64 def add_finalizer(query, result_value, key, finalizer) @finalizers ||= {}.compare_by_identity f_for_query = @finalizers[query] ||= {}.compare_by_identity f_for_result = f_for_query[result_value] ||= {}.compare_by_identity if (f = f_for_result[key]) if f.is_a?(Array) f << finalizer else f_for_result[key] = [f, finalizer] end else f_for_result[key] = finalizer end nil end
Returns
-
void
Source
# File lib/graphql/execution/runner.rb, line 52 def add_step(step) @dataloader.append_job(step) end
Source
# File lib/graphql/execution/runner.rb, line 80 def execute previous_multiplex = Fiber[:__graphql_current_multiplex] Fiber[:__graphql_current_multiplex] = @multiplex isolated_steps = [[]] trace = @multiplex.current_trace queries = @multiplex.queries multiplex_analyzers = @schema.multiplex_analyzers if @multiplex.max_complexity multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity] end trace.execute_multiplex(multiplex: @multiplex) do trace.begin_analyze_multiplex(@multiplex, multiplex_analyzers) @schema.analysis_engine.analyze_multiplex(@multiplex, multiplex_analyzers) trace.end_analyze_multiplex(@multiplex, multiplex_analyzers) results = {}.compare_by_identity queries.each do |query| if query.validate && !query.valid? results[query] = { "errors" => query.static_errors.map(&:to_h) } next end root_type = query.root_type if root_type.non_null? root_type = root_type.of_type end root_value = query.root_value if resolves_lazies root_value = schema.sync_lazy(root_value) end trace.execute_query(query: query) do begin_execute(isolated_steps, results, query, root_type, root_value) end rescue GraphQL::RuntimeError => err err.ast_node = query.selected_operation err.path = query.path query.context.add_error(err) end trace.execute_query_lazy(query: @multiplex.queries.size == 1 ? @multiplex.queries.first : nil, multiplex: @multiplex) do while (next_isolated_steps = isolated_steps.shift) next_isolated_steps.each do |step| add_step(step) end @dataloader.run end end queries.map do |query| result = results[query] fin_result = if (!@finalizers&.key?(query) && query.context.errors.empty?) || !query.valid? result else if result data = result["data"] data = Finalize.new(query, data, self).run end errors = [] query.context.errors.each do |err| if err.respond_to?(:to_h) errors << err.to_h end end res_h = {} if !errors.empty? res_h["errors"] = errors end res_h["data"] = data res_h end query.result_values = fin_result if query.context.namespace?(:__query_result_extensions__) query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__) end query.result end rescue SystemStackError => err queries.map do |query| @schema.query_stack_error(query, err) query.result_values ||= { "errors" => query.context.errors.map(&:to_h) } query.result end rescue Exception # Assign values here so that the query's `@executed` becomes true queries.map { |q| q.result_values ||= {} } raise end ensure Fiber[:__graphql_current_multiplex] = previous_multiplex end
# File lib/graphql/execution/runner.rb, line 179 def gather_selections(type_defn, ast_selections, selections_step, query, all_selections, prototype_result, into:) ast_selections.each do |ast_selection| next if !directives_include?(query, ast_selection) case ast_selection when GraphQL::Language::Nodes::Field key = ast_selection.alias || ast_selection.name step = into[key] ||= begin prototype_result[key] = nil FieldResolveStep.new( selections_step: selections_step, key: key, parent_type: type_defn, runner: self, ) end step.append_selection(ast_selection) when GraphQL::Language::Nodes::InlineFragment type_condition = ast_selection.type&.name if type_condition.nil? || type_condition_applies?(query.context, type_defn, type_condition) if uses_runtime_directives && !ast_selection.directives.empty? all_selections << (into = { __node: ast_selection }) all_selections << (prototype_result = {}) end gather_selections(type_defn, ast_selection.selections, selections_step, query, all_selections, prototype_result, into: into) end when GraphQL::Language::Nodes::FragmentSpread fragment_definition = query.fragments[ast_selection.name] type_condition = fragment_definition.type.name if type_condition_applies?(query.context, type_defn, type_condition) if uses_runtime_directives && !ast_selection.directives.empty? all_selections << (into = { __node: ast_selection }) all_selections << (prototype_result = {}) end gather_selections(type_defn, fragment_definition.selections, selections_step, query, all_selections, prototype_result, into: into) end else raise ArgumentError, "Unsupported graphql selection node: #{ast_selection.class} (#{ast_selection.inspect})" end end end
Source
# File lib/graphql/execution/runner.rb, line 222 def lazy?(object) obj_class = object.class is_lazy = @lazy_cache[obj_class] if is_lazy.nil? is_lazy = @lazy_cache[obj_class] = @schema.lazy?(object) end is_lazy end
# File lib/graphql/execution/runner.rb, line 231 def type_condition_applies?(context, concrete_type, type_name) if type_name == concrete_type.graphql_name true else abs_t = @schema.get_type(type_name, context) p_types = @schema.possible_types(abs_t, context) c_p_types = @schema.possible_types(concrete_type, context) p_types.any? { |t| c_p_types.include?(t) } end end