lib/graphql/schema/reduce_types.rb
module GraphQL class Schema module ReduceTypes # @param types [Array<GraphQL::BaseType>] members of a schema to crawl for all member types # @return [GraphQL::Schema::TypeMap] `{name => Type}` pairs derived from `types` def self.reduce(types) type_map = GraphQL::Schema::TypeMap.new types.each do |type| reduce_type(type, type_map, type.name) end type_map end private # Based on `type`, add members to `type_hash`. # If `type` has already been visited, just return the `type_hash` as-is def self.reduce_type(type, type_hash, context_description) if !type.is_a?(GraphQL::BaseType) message = "#{context_description} has an invalid type: must be an instance of GraphQL::BaseType, not #{type.class.inspect} (#{type.inspect})" raise GraphQL::Schema::InvalidTypeError.new(message) end type = type.unwrap # Don't re-visit a type if !type_hash.fetch(type.name, nil).equal?(type) validate_type(type, context_description) type_hash[type.name] = type crawl_type(type, type_hash, context_description) end end def self.crawl_type(type, type_hash, context_description) if type.kind.fields? type.all_fields.each do |field| reduce_type(field.type, type_hash, "Field #{type.name}.#{field.name}") field.arguments.each do |name, argument| reduce_type(argument.type, type_hash, "Argument #{name} on #{type.name}.#{field.name}") end end end if type.kind.object? type.interfaces.each do |interface| reduce_type(interface, type_hash, "Interface on #{type.name}") end end if type.kind.union? type.possible_types.each do |possible_type| reduce_type(possible_type, type_hash, "Possible type for #{type.name}") end end if type.kind.input_object? type.arguments.each do |argument_name, argument| reduce_type(argument.type, type_hash, "Input field #{type.name}.#{argument_name}") end end end def self.validate_type(type, context_description) error_message = GraphQL::Schema::Validation.validate(type) if error_message raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}") end end end end end