Class: GraphQL::InternalRepresentation::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/internal_representation/node.rb

Constant Summary collapse

DEFAULT_TYPED_CHILDREN =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Proc.new { |h, k| h[k] = {} }
NO_TYPED_CHILDREN =

A specialized, reusable object for leaf nodes.

Hash.new({}.freeze)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, owner_type:, query:, return_type:, parent:, ast_nodes: [], definitions: []) ⇒ Node

Returns a new instance of Node.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/graphql/internal_representation/node.rb', line 65

def initialize(
    name:, owner_type:, query:, return_type:, parent:,
    ast_nodes: [],
    definitions: []
  )
  @name = name
  @query = query
  @owner_type = owner_type
  @parent = parent
  @typed_children = nil
  @scoped_children = Hash.new { |h1, k1| h1[k1] = {} }
  @ast_nodes = ast_nodes
  @definitions = definitions
  @return_type = return_type
end

Instance Attribute Details

#ast_nodesArray<Language::Nodes::AbstractNode> (readonly)

Returns AST nodes which are represented by this node.

Returns:



54
55
56
# File 'lib/graphql/internal_representation/node.rb', line 54

def ast_nodes
  @ast_nodes
end

#definitionsArray<GraphQL::Field> (readonly)

Returns Field definitions for this node (there should only be one!).

Returns:

  • (Array<GraphQL::Field>)

    Field definitions for this node (there should only be one!)



57
58
59
# File 'lib/graphql/internal_representation/node.rb', line 57

def definitions
  @definitions
end

#nameString (readonly)

Returns the name this node has in the response.

Returns:

  • (String)

    the name this node has in the response



14
15
16
# File 'lib/graphql/internal_representation/node.rb', line 14

def name
  @name
end

#owner_typeGraphQL::ObjectType

Returns:



17
18
19
# File 'lib/graphql/internal_representation/node.rb', line 17

def owner_type
  @owner_type
end

#parentInternalRepresentation::Node?



63
64
65
# File 'lib/graphql/internal_representation/node.rb', line 63

def parent
  @parent
end

#queryGraphQL::Query (readonly)

Returns:



158
159
160
# File 'lib/graphql/internal_representation/node.rb', line 158

def query
  @query
end

#return_typeGraphQL::BaseType (readonly)

Returns The expected wrapped type this node must return.

Returns:



60
61
62
# File 'lib/graphql/internal_representation/node.rb', line 60

def return_type
  @return_type
end

#scoped_childrenHash<GraphQL::BaseType, Hash<String => Node>> (readonly)

These children correspond closely to scopes in the AST. Keys may be abstract types. They're assumed to be read-only after rewrite is finished because #typed_children is derived from them.

Using #scoped_children during the rewrite step reduces the overhead of reifying abstract types because they're only reified after the rewrite.

Returns:



51
52
53
# File 'lib/graphql/internal_representation/node.rb', line 51

def scoped_children
  @scoped_children
end

Instance Method Details

#==(other) ⇒ Object



94
95
96
97
98
99
100
101
102
103
# File 'lib/graphql/internal_representation/node.rb', line 94

def ==(other)
  other.is_a?(self.class) &&
    other.name == name &&
    other.parent == parent &&
    other.return_type == return_type &&
    other.owner_type == owner_type &&
    other.scoped_children == scoped_children &&
    other.definitions == definitions &&
    other.ast_nodes == ast_nodes
end

#argumentsObject



109
110
111
# File 'lib/graphql/internal_representation/node.rb', line 109

def arguments
  @query.arguments_for(self, definition)
end

#ast_nodeObject



120
121
122
# File 'lib/graphql/internal_representation/node.rb', line 120

def ast_node
  @ast_node ||= ast_nodes.first
end

#deep_merge_node(new_parent, scope: nil, merge_self: true) ⇒ Object

Merge selections from new_parent into self. Selections are merged in place, not copied.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/graphql/internal_representation/node.rb', line 132

def deep_merge_node(new_parent, scope: nil, merge_self: true)
  if merge_self
    @ast_nodes |= new_parent.ast_nodes
    @definitions |= new_parent.definitions
  end
  new_sc = new_parent.scoped_children
  if new_sc.any?
    scope ||= Scope.new(@query, @return_type.unwrap)
    new_sc.each do |obj_type, new_fields|
      inner_scope = scope.enter(obj_type)
      inner_scope.each do |scoped_type|
        prev_fields = @scoped_children[scoped_type]
        new_fields.each do |name, new_node|
          prev_node = prev_fields[name]
          if prev_node
            prev_node.deep_merge_node(new_node)
          else
            prev_fields[name] = new_node
          end
        end
      end
    end
  end
end

#definitionObject



113
114
115
116
117
118
# File 'lib/graphql/internal_representation/node.rb', line 113

def definition
  @definition ||= begin
    first_def = @definitions.first
    first_def && @query.get_field(@owner_type, first_def.name)
  end
end

#definition_nameObject



105
106
107
# File 'lib/graphql/internal_representation/node.rb', line 105

def definition_name
  definition && definition.name
end

#initialize_copy(other_node) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/graphql/internal_representation/node.rb', line 81

def initialize_copy(other_node)
  super
  # Bust some caches:
  @typed_children = nil
  @definition = nil
  @definition_name = nil
  @ast_node = nil
  # Shallow-copy some state:
  @scoped_children = other_node.scoped_children.dup
  @ast_nodes = other_node.ast_nodes.dup
  @definitions = other_node.definitions.dup
end

#inspectObject



124
125
126
127
128
# File 'lib/graphql/internal_representation/node.rb', line 124

def inspect
  all_children_names = scoped_children.values.map(&:keys).flatten.uniq.join(", ")
  all_locations = ast_nodes.map {|n| "#{n.line}:#{n.col}" }.join(", ")
  "#<Node #{@owner_type}.#{@name} -> #{@return_type} {#{all_children_names}} @ [#{all_locations}] #{object_id}>"
end

#subscription_topicObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/graphql/internal_representation/node.rb', line 160

def subscription_topic
  @subscription_topic ||= begin
    scope = if definition.subscription_scope
      @query.context[definition.subscription_scope]
    else
      nil
    end
    Subscriptions::Event.serialize(
      definition_name,
      @query.arguments_for(self, definition),
      definition,
      scope: scope
    )
  end
end

#typed_childrenHash<GraphQL::ObjectType, Hash<String => Node>>

Each key is a ObjectType which this selection may be made on. The values for that key are selections which apply to that type.

This value is derived from #scoped_children after the rewrite is finished.

Returns:



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/graphql/internal_representation/node.rb', line 24

def typed_children
  @typed_children ||= begin
    if @scoped_children.any?
      new_tc = Hash.new(&DEFAULT_TYPED_CHILDREN)
      all_object_types = Set.new
      scoped_children.each_key { |t| all_object_types.merge(@query.possible_types(t)) }
      # Remove any scoped children which don't follow this return type
      # (This can happen with fragment merging where lexical scope is lost)
      all_object_types &= @query.possible_types(@return_type.unwrap)
      all_object_types.each do |t|
        new_tc[t] = get_typed_children(t)
      end
      new_tc
    else
      NO_TYPED_CHILDREN
    end

  end
end