lib/graphql/execution/multiplex.rb in graphql-2.0.13 vs lib/graphql/execution/multiplex.rb in graphql-2.0.14
- old
+ new
@@ -21,17 +21,14 @@
# one of these errors in one query will not affect the other queries.
#
# @see {Schema#multiplex} for public API
# @api private
class Multiplex
- # Used internally to signal that the query shouldn't be executed
- # @api private
- NO_OPERATION = {}.freeze
-
include Tracing::Traceable
attr_reader :context, :queries, :schema, :max_complexity, :dataloader
+
def initialize(schema:, queries:, context:, max_complexity:)
@schema = schema
@queries = queries
@queries.each { |q| q.multiplex = self }
@context = context
@@ -40,121 +37,9 @@
# Support `context: {backtrace: true}`
if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
@tracers << GraphQL::Backtrace::Tracer
end
@max_complexity = max_complexity
- end
-
- class << self
- # @param schema [GraphQL::Schema]
- # @param queries [Array<GraphQL::Query, Hash>]
- # @param context [Hash]
- # @param max_complexity [Integer, nil]
- # @return [Array<Hash>] One result per query
- def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
- queries = query_options.map do |opts|
- case opts
- when Hash
- GraphQL::Query.new(schema, nil, **opts)
- when GraphQL::Query
- opts
- else
- raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
- end
- end
-
- multiplex = self.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
- multiplex.trace("execute_multiplex", { multiplex: multiplex }) do
- GraphQL::Execution::Instrumentation.apply_instrumenters(multiplex) do
- schema = multiplex.schema
- multiplex_analyzers = schema.multiplex_analyzers
- if multiplex.max_complexity
- multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
- end
-
- schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
-
- begin
- multiplex.schema.query_execution_strategy.begin_multiplex(multiplex)
- # Do as much eager evaluation of the query as possible
- results = []
- queries.each_with_index do |query, idx|
- multiplex.dataloader.append_job { begin_query(results, idx, query, multiplex) }
- end
-
- multiplex.dataloader.run
-
- # Then, work through lazy results in a breadth-first way
- multiplex.dataloader.append_job {
- multiplex.schema.query_execution_strategy.finish_multiplex(results, multiplex)
- }
- multiplex.dataloader.run
-
- # Then, find all errors and assign the result to the query object
- results.each_with_index do |data_result, idx|
- query = queries[idx]
- finish_query(data_result, query, multiplex)
- # Get the Query::Result, not the Hash
- results[idx] = query.result
- end
-
- results
- rescue Exception
- # TODO rescue at a higher level so it will catch errors in analysis, too
- # Assign values here so that the query's `@executed` becomes true
- queries.map { |q| q.result_values ||= {} }
- raise
- end
- end
- end
- end
-
- # @param query [GraphQL::Query]
- def begin_query(results, idx, query, multiplex)
- operation = query.selected_operation
- result = if operation.nil? || !query.valid? || query.context.errors.any?
- NO_OPERATION
- else
- begin
- query.schema.query_execution_strategy.begin_query(query, multiplex)
- rescue GraphQL::ExecutionError => err
- query.context.errors << err
- NO_OPERATION
- end
- end
- results[idx] = result
- nil
- end
-
- private
-
- # @param data_result [Hash] The result for the "data" key, if any
- # @param query [GraphQL::Query] The query which was run
- # @return [Hash] final result of this query, including all values and errors
- def finish_query(data_result, query, multiplex)
- # Assign the result so that it can be accessed in instrumentation
- query.result_values = if data_result.equal?(NO_OPERATION)
- if !query.valid? || query.context.errors.any?
- # A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
- { "errors" => query.static_errors.map(&:to_h) }
- else
- data_result
- end
- else
- # Use `context.value` which was assigned during execution
- result = query.schema.query_execution_strategy.finish_query(query, multiplex)
-
- if query.context.errors.any?
- error_result = query.context.errors.map(&:to_h)
- result["errors"] = error_result
- end
-
- result
- end
- if query.context.namespace?(:__query_result_extensions__)
- query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
- end
- end
end
end
end
end