diff --git a/lib/graphql/execution/interpreter.rb b/lib/graphql/execution/interpreter.rb index afe878e9e4..bd716f3fbc 100644 --- a/lib/graphql/execution/interpreter.rb +++ b/lib/graphql/execution/interpreter.rb @@ -84,13 +84,11 @@ def run_all(schema, query_options, context: {}, max_complexity: schema.max_compl # Then, work through lazy results in a breadth-first way multiplex.dataloader.append_job { query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil - queries = multiplex ? multiplex.queries : [query] - final_values = queries.map do |query| + queries.each do |query| runtime = query.context.namespace(:interpreter_runtime)[:runtime] # it might not be present if the query has an error runtime ? runtime.final_result : nil end - final_values.compact! multiplex.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader) end @@ -147,6 +145,62 @@ def run_all(schema, query_options, context: {}, max_complexity: schema.max_compl end end end + + def run_partials(schema, partials, context:) + multiplex = Execution::Multiplex.new(schema: schema, queries: partials, context: context, max_complexity: nil) + dataloader = multiplex.dataloader + lazies_at_depth = Hash.new { |h, k| h[k] = [] } + + partials.each do |partial| + dataloader.append_job { + runtime = Runtime.new(query: partial, lazies_at_depth: lazies_at_depth) + partial.context.namespace(:interpreter_runtime)[:runtime] = runtime + # TODO tracing? + runtime.run_eager + } + end + + dataloader.run + + dataloader.append_job { + partials.each do |partial| + runtime = partial.context.namespace(:interpreter_runtime)[:runtime] + runtime.final_result + end + # TODO tracing? + Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader) + } + + dataloader.run + + partials.map do |partial| + # Assign the result so that it can be accessed in instrumentation + data_result = partial.context.namespace(:interpreter_runtime)[:runtime].final_result + partial.result_values = if data_result.equal?(NO_OPERATION) + if !partial.context.errors.empty? + { "errors" => partial.context.errors.map(&:to_h) } + else + data_result + end + else + result = {} + + if !partial.context.errors.empty? + error_result = partial.context.errors.map(&:to_h) + result["errors"] = error_result + end + + result["data"] = data_result + + result + end + if partial.context.namespace?(:__query_result_extensions__) + partial.result_values["extensions"] = partial.context.namespace(:__query_result_extensions__) + end + # Partial::Result + partial.result + end + end end class ListResultFailedError < GraphQL::Error diff --git a/lib/graphql/query.rb b/lib/graphql/query.rb index aba9dc1e38..8c475ee29c 100644 --- a/lib/graphql/query.rb +++ b/lib/graphql/query.rb @@ -258,7 +258,7 @@ def operations # @return [Array] def run_partials(partials_hashes) partials = partials_hashes.map { |partial_options| Partial.new(query: self, **partial_options) } - Execution::Interpreter.run_all(@schema, partials, context: @context) + Execution::Interpreter.run_partials(@schema, partials, context: @context) end # Get the result for this query, executing it once diff --git a/lib/graphql/query/partial.rb b/lib/graphql/query/partial.rb index 03323bb086..b1ff03998f 100644 --- a/lib/graphql/query/partial.rb +++ b/lib/graphql/query/partial.rb @@ -34,25 +34,10 @@ def result @result ||= GraphQL::Query::Result.new(query: self, values: result_values) end - def valid? - true - end - - def analyzers - EmptyObjects::EMPTY_ARRAY - end - def current_trace @query.current_trace end - def analysis_errors=(_errs) - end - - def subscription? - false - end - def schema @query.schema end