123456789_123456789_123456789_123456789_123456789_

Class: GraphQL::Client::Definition

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Module
Instance Chain:
self, Module
Inherits: Module
  • Object
Defined in: lib/graphql/client/definition.rb

Overview

Definitions are constructed by Client.parse and wrap a parsed AST of the query string as well as hold references to any external query definition dependencies.

Definitions MUST be assigned to a constant.

Constant Summary

Class Method Summary

Instance Attribute Summary

  • #client readonly

    Internal: Get associated owner ::GraphQL::Client instance.

  • #definition_node readonly

    Internal: Get underlying operation or fragment definition AST node for definition.

  • #document readonly

    Public: Get document with only the definitions needed to perform this operation.

  • #schema_class readonly

    Internal root schema class for definition.

  • #source_document readonly

    Internal: Get original document that created this definition, without any additional dependencies.

  • #source_location readonly

    Public: Returns the Ruby source filename and line number containing this definition was not defined in Ruby.

Instance Method Summary

Constructor Details

.new(client:, document:, source_document:, ast_node:, source_location:) ⇒ Definition

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 28

def initialize(client:, document:, source_document:, ast_node:, source_location:)
  @client = client
  @document = document
  @source_document = source_document
  @definition_node = ast_node
  @source_location = source_location

  definition_type = case ast_node
  when GraphQL::Language::Nodes::OperationDefinition
    case ast_node.operation_type
    when "mutation"
      @client.schema.mutation
    when "subscription"
      @client.schema.subscription
    when "query", nil
      @client.schema.query
    else
      raise "Unexpected operation_type: #{ast_node.operation_type}"
    end
  when GraphQL::Language::Nodes::FragmentDefinition
    @client.get_type(ast_node.type.name)
  else
    raise "Unexpected ast_node: #{ast_node}"
  end

  @schema_class = client.types.define_class(self, [ast_node], definition_type)

  # Clear cache only needed during initialization
  @indexes = nil
end

Class Method Details

.for(ast_node:, **kargs)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 17

def self.for(ast_node:, **kargs)
  case ast_node
  when Language::Nodes::OperationDefinition
    OperationDefinition.new(ast_node: ast_node, **kargs)
  when Language::Nodes::FragmentDefinition
    FragmentDefinition.new(ast_node: ast_node, **kargs)
  else
    raise TypeError, "expected node to be a definition type, but was #{ast_node.class}"
  end
end

Instance Attribute Details

#client (readonly)

Internal: Get associated owner ::GraphQL::Client instance.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 60

attr_reader :client

#definition_node (readonly)

Internal: Get underlying operation or fragment definition AST node for definition.

Returns OperationDefinition or FragmentDefinition object.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 71

attr_reader :definition_node

#document (readonly)

Public: Get document with only the definitions needed to perform this operation.

Returns GraphQL::Language::Nodes::Document with one OperationDefinition and any FragmentDefinition dependencies.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 101

attr_reader :document

#schema_class (readonly)

Internal root schema class for definition. Returns Schema::ObjectType or Schema::PossibleTypes.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 65

attr_reader :schema_class

#source_document (readonly)

Internal: Get original document that created this definition, without any additional dependencies.

Returns GraphQL::Language::Nodes::Document.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 77

attr_reader :source_document

#source_location (readonly)

Public: Returns the Ruby source filename and line number containing this definition was not defined in Ruby.

Returns Array pair of [String, Fixnum].

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 107

attr_reader :source_location

Instance Method Details

#cast_object(obj) (private)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 160

def cast_object(obj)
  if obj.class.is_a?(GraphQL::Client::Schema::ObjectType)
    unless obj._spreads.include?(definition_node.name)
      raise TypeError, "#{definition_node.name} is not included in #{obj.source_definition.name}"
    end
    schema_class.cast(obj.to_h, obj.errors)
  else
    raise TypeError, "unexpected #{obj.class}"
  end
end

#definition_name Also known as: #operation_name

Public: Global name of definition in client document.

Returns a ::GraphQL safe name of the Ruby constant String.

"Users::UserQuery" #=> "Users__UserQuery"

Returns String.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 86

def definition_name
  return @definition_name if defined?(@definition_name)

  if name
    @definition_name = name.gsub("::", "__").freeze
  else
    "#{self.class.name}_#{object_id}".gsub("::", "__").freeze
  end
end

#flatten_spreads(node) (private)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 187

def flatten_spreads(node)
  spreads = []
  node.selections.each do |selection|
    case selection
    when Language::Nodes::FragmentSpread
      spreads << selection
    when Language::Nodes::InlineFragment
      spreads.concat(flatten_spreads(selection))
    else
      # Do nothing, not a spread
    end
  end
  spreads
end

#index_node_definitions(visitor) (private)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 202

def index_node_definitions(visitor)
  current_definition = nil
  enter_definition = ->(node, _parent) { current_definition = node }
  leave_definition = ->(node, _parent) { current_definition = nil }

  visitor[GraphQL::Language::Nodes::FragmentDefinition].enter << enter_definition
  visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << leave_definition
  visitor[GraphQL::Language::Nodes::OperationDefinition].enter << enter_definition
  visitor[GraphQL::Language::Nodes::OperationDefinition].leave << leave_definition

  definitions = {}
  on_node = ->(node, _parent) { definitions[node] = current_definition }
  visitor[GraphQL::Language::Nodes::Field] << on_node
  visitor[GraphQL::Language::Nodes::FragmentDefinition] << on_node
  visitor[GraphQL::Language::Nodes::InlineFragment] << on_node
  visitor[GraphQL::Language::Nodes::OperationDefinition] << on_node
  definitions
end

#index_spreads(visitor) (private)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 173

def index_spreads(visitor)
  spreads = {}
  on_node = ->(node, _parent) do
    node_spreads = flatten_spreads(node).map(&:name)
    spreads[node] = node_spreads.empty? ? EMPTY_SET : Set.new(node_spreads).freeze
  end

  visitor[GraphQL::Language::Nodes::Field] << on_node
  visitor[GraphQL::Language::Nodes::FragmentDefinition] << on_node
  visitor[GraphQL::Language::Nodes::OperationDefinition] << on_node

  spreads
end

#indexes

Internal: Nodes AST indexes.

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 148

def indexes
  @indexes ||= begin
    visitor = GraphQL::Language::Visitor.new(document)
    definitions = index_node_definitions(visitor)
    spreads = index_spreads(visitor)
    visitor.visit
    { definitions: definitions, spreads: spreads }
  end
end

#new(obj, errors = Errors.new)

[ GitHub ]

  
# File 'lib/graphql/client/definition.rb', line 109

def new(obj, errors = Errors.new)
  case schema_class
  when GraphQL::Client::Schema::PossibleTypes
    case obj
    when NilClass
      obj
    else
      cast_object(obj)
    end
  when GraphQL::Client::Schema::ObjectType::WithDefinition
    case obj
    when schema_class.klass
      if obj._definer == schema_class
        obj
      else
        cast_object(obj)
      end
    when nil
      nil
    when Hash
      schema_class.new(obj, errors)
    else
      cast_object(obj)
    end
  when GraphQL::Client::Schema::ObjectType
    case obj
    when nil, schema_class
      obj
    when Hash
      schema_class.new(obj, errors)
    else
      cast_object(obj)
    end
  else
    raise TypeError, "unexpected #{schema_class}"
  end
end