class GraphQL::Schema::Visibility::Visit
Public Class Methods
Source
# File lib/graphql/schema/visibility/visit.rb, line 7 def initialize(schema, &visit_block) @schema = schema @late_bound_types = nil @unvisited_types = nil # These accumulate between calls to prevent re-visiting the same types @visited_types = Set.new.compare_by_identity @visited_directives = Set.new.compare_by_identity @visit_block = visit_block end
Public Instance Methods
Source
# File lib/graphql/schema/visibility/visit.rb, line 29 def entry_point_directives @schema.directives.values end
Source
# File lib/graphql/schema/visibility/visit.rb, line 17 def entry_point_types ept = [ @schema.query, @schema.mutation, @schema.subscription, *@schema.introspection_system.types.values, *@schema.orphan_types, ] ept.compact! ept end
# File lib/graphql/schema/visibility/visit.rb, line 33 def visit_each(types: entry_point_types, directives: entry_point_directives) @unvisited_types && raise("Can't re-enter `visit_each` on this Visit (another visit is already in progress)") @unvisited_types = types @late_bound_types = [] directives_to_visit = directives while !@unvisited_types.empty? || !@late_bound_types.empty? while (type = @unvisited_types.pop) if @visited_types.add?(type) && @visit_block.call(type) directives_to_visit.concat(type.directives) case type.kind.name when "OBJECT", "INTERFACE" type.interface_type_memberships.each do |itm| # Late-bound interfaces are stored as a String or LateBoundType instead of a TypeMembership append_unvisited_type(type, itm.respond_to?(:abstract_type) ? itm.abstract_type : itm) end if type.kind.interface? type.orphan_types.each do |orphan_type| append_unvisited_type(type, orphan_type) end end type.all_field_definitions.each do |field| field.ensure_loaded if @visit_block.call(field) directives_to_visit.concat(field.directives) append_unvisited_type(type, field.type.unwrap) field.all_argument_definitions.each do |argument| if @visit_block.call(argument) directives_to_visit.concat(argument.directives) append_unvisited_type(field, argument.type.unwrap) end end end end when "INPUT_OBJECT" type.all_argument_definitions.each do |argument| if @visit_block.call(argument) directives_to_visit.concat(argument.directives) append_unvisited_type(type, argument.type.unwrap) end end when "UNION" type.type_memberships.each do |tm| append_unvisited_type(type, tm.object_type) end when "ENUM" type.all_enum_value_definitions.each do |val| if @visit_block.call(val) directives_to_visit.concat(val.directives) end end when "SCALAR" # pass -- nothing else to visit else raise "Invariant: unhandled type kind: #{type.kind.inspect}" end end end directives_to_visit.each do |dir| dir_class = dir.is_a?(Class) ? dir : dir.class if @visited_directives.add?(dir_class) && @visit_block.call(dir_class) dir_class.all_argument_definitions.each do |arg_defn| if @visit_block.call(arg_defn) directives_to_visit.concat(arg_defn.directives) append_unvisited_type(dir_class, arg_defn.type.unwrap) end end end end missed_late_types_streak = 0 while (owner, late_type = @late_bound_types.shift) if (late_type.is_a?(String) && (type = Member::BuildType.constantize(late_type))) || (late_type.is_a?(LateBoundType) && (type = @visited_types.find { |t| t.graphql_name == late_type.graphql_name })) missed_late_types_streak = 0 # might succeed next round update_type_owner(owner, type) append_unvisited_type(owner, type) else # Didn't find it -- keep trying missed_late_types_streak += 1 @late_bound_types << [owner, late_type] if missed_late_types_streak == @late_bound_types.size raise UnresolvedLateBoundTypeError.new(type: late_type) end end end end @unvisited_types = nil nil end