class GraphQL::Analysis::QueryComplexity
Calculate the complexity of a query, using Field#complexity values.
Public Class Methods
Source
# File lib/graphql/analysis/query_complexity.rb, line 9 def initialize(query) super @skip_introspection_fields = !query.schema.max_complexity_count_introspection_fields @complexities_on_type_by_query = {} @intersect_cache = Hash.new { |h, k| h[k] = {}.compare_by_identity }.compare_by_identity @possible_types_cache = {}.compare_by_identity end
State for the query complexity calculation: - complexities_on_type holds complexity scores for each type
Calls superclass method
GraphQL::Analysis::Analyzer::new
Public Instance Methods
# File lib/graphql/analysis/query_complexity.rb, line 91 def on_enter_field(node, parent, visitor) # We don't want to visit fragment definitions, # we'll visit them when we hit the spreads instead return if visitor.visiting_fragment_definition? return if visitor.skipping? return if @skip_introspection_fields && visitor.field_definition.introspection? parent_type = visitor.parent_type_definition field_key = node.alias || node.name # Find or create a complexity scope stack for this query. scopes_stack = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)] # Find or create the complexity costing node for this field. scope = scopes_stack.last[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path) scope.nodes.push(node) scopes_stack.push(scope) end
# File lib/graphql/analysis/query_complexity.rb, line 109 def on_leave_field(node, parent, visitor) # We don't want to visit fragment definitions, # we'll visit them when we hit the spreads instead return if visitor.visiting_fragment_definition? return if visitor.skipping? return if @skip_introspection_fields && visitor.field_definition.introspection? scopes_stack = @complexities_on_type_by_query[visitor.query] scopes_stack.pop end
Source
# File lib/graphql/analysis/query_complexity.rb, line 18 def result case subject.schema.complexity_cost_calculation_mode_for(subject.context) when :future max_possible_complexity when :legacy max_possible_complexity(mode: :legacy) when :compare future_complexity = max_possible_complexity legacy_complexity = max_possible_complexity(mode: :legacy) if future_complexity != legacy_complexity subject.schema.legacy_complexity_cost_calculation_mismatch(subject, future_complexity, legacy_complexity) else future_complexity end when nil subject.logger.warn <<~MESSAGE GraphQL-Ruby's complexity cost system is getting some "breaking fixes" in a future version. See the migration notes at https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#complexity_cost_calculation_mode_for-class_method To opt into the future behavior, configure your schema (#{subject.schema.name ? subject.schema.name : subject.schema.ancestors}) with: complexity_cost_calculation_mode(:future) # or `:legacy`, `:compare` MESSAGE max_possible_complexity(mode: :legacy) else raise ArgumentError, "Expected `:future`, `:legacy`, `:compare`, or `nil` from `#{query.schema}.complexity_cost_calculation_mode_for` but got: #{query.schema.complexity_cost_calculation_mode.inspect}" end end
Override this method to use the complexity result