module GraphQL module Language module Nodes # AbstractNode creates classes who: # - require their keyword arguments, throw ArgumentError if they don't match # - expose accessors for keyword arguments class AbstractNode attr_accessor :line, :col # @param options [Hash] Must contain all attributes defined by {required_attrs}, may also include `position_source` def initialize(options={}) if options.key?(:position_source) position_source = options.delete(:position_source) @line, @col = position_source.line_and_column elsif options.key?(:line) @line = options.delete(:line) @col = options.delete(:col) end initialize_node(options) end # This is called with node-specific options def initialize_node(options={}) raise NotImplementedError end # @return [GraphQL::Language::Nodes::AbstractNode] all nodes in the tree below this one def children self.class.child_attributes .map { |attr_name| public_send(attr_name) } .flatten end class << self def child_attributes(*attr_names) @child_attributes ||= [] @child_attributes += attr_names end end def position [line, col] end def to_query_string Generation.generate(self) end end class WrapperType < AbstractNode attr_accessor :of_type def initialize_node(of_type: nil) @of_type = of_type end def children [].freeze end end class NameOnlyNode < AbstractNode attr_accessor :name def initialize_node(name: nil) @name = name end def children [].freeze end end class Argument < AbstractNode attr_accessor :name, :value def initialize_node(name: nil, value: nil) @name = name @value = value end def children [value].flatten.select { |v| v.is_a?(AbstractNode) } end end class Directive < AbstractNode attr_accessor :name, :arguments child_attributes :arguments def initialize_node(name: nil, arguments: []) @name = name @arguments = arguments end end class Document < AbstractNode attr_accessor :definitions child_attributes :definitions def initialize_node(definitions: []) @definitions = definitions end end class Enum < NameOnlyNode; end class Field < AbstractNode attr_accessor :name, :alias, :arguments, :directives, :selections child_attributes :arguments, :directives, :selections def initialize_node(name: nil, arguments: [], directives: [], selections: [], **kwargs) @name = name # oops, alias is a keyword: @alias = kwargs.fetch(:alias, nil) @arguments = arguments @directives = directives @selections = selections end end class FragmentDefinition < AbstractNode attr_accessor :name, :type, :directives, :selections child_attributes :directives, :selections def initialize_node(name: nil, type: nil, directives: [], selections: []) @name = name @type = type @directives = directives @selections = selections end end class FragmentSpread < AbstractNode attr_accessor :name, :directives child_attributes :directives def initialize_node(name: nil, directives: []) @name = name @directives = directives end end class InlineFragment < AbstractNode attr_accessor :type, :directives, :selections child_attributes :directives, :selections def initialize_node(type: nil, directives: [], selections: []) @type = type @directives = directives @selections = selections end end class InputObject < AbstractNode attr_accessor :arguments child_attributes :arguments def initialize_node(arguments: []) @arguments = arguments end def to_h(options={}) arguments.inject({}) do |memo, pair| v = pair.value memo[pair.name] = v.is_a?(InputObject) ? v.to_h : v memo end end end class ListType < WrapperType; end class NonNullType < WrapperType; end class OperationDefinition < AbstractNode attr_accessor :operation_type, :name, :variables, :directives, :selections child_attributes :variables, :directives, :selections def initialize_node(operation_type: nil, name: nil, variables: [], directives: [], selections: []) @operation_type = operation_type @name = name @variables = variables @directives = directives @selections = selections end end class TypeName < NameOnlyNode; end class VariableDefinition < AbstractNode attr_accessor :name, :type, :default_value def initialize_node(name: nil, type: nil, default_value: nil) @name = name @type = type @default_value = default_value end end class VariableIdentifier < NameOnlyNode; end end end end