Class: GraphQL::InternalRepresentation::Node

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

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.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/graphql/internal_representation/node.rb', line 54

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:



43
44
45
# File 'lib/graphql/internal_representation/node.rb', line 43

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!)



46
47
48
# File 'lib/graphql/internal_representation/node.rb', line 46

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



6
7
8
# File 'lib/graphql/internal_representation/node.rb', line 6

def name
  @name
end

#owner_typeGraphQL::ObjectType

Returns:



9
10
11
# File 'lib/graphql/internal_representation/node.rb', line 9

def owner_type
  @owner_type
end

#parentInternalRepresentation::Node?



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

def parent
  @parent
end

#return_typeGraphQL::BaseType (readonly)

Returns:



49
50
51
# File 'lib/graphql/internal_representation/node.rb', line 49

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:



40
41
42
# File 'lib/graphql/internal_representation/node.rb', line 40

def scoped_children
  @scoped_children
end

Instance Method Details

#==(other) ⇒ Object



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

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

#ast_nodeObject



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

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.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/graphql/internal_representation/node.rb', line 117

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
  scope ||= Scope.new(@query, @return_type)
  new_parent.scoped_children.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

#definitionObject



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

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

#definition_nameObject



94
95
96
# File 'lib/graphql/internal_representation/node.rb', line 94

def definition_name
  definition && definition.name
end

#initialize_copy(other_node) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/graphql/internal_representation/node.rb', line 70

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



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

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

#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:



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/graphql/internal_representation/node.rb', line 16

def typed_children
  @typed_childen ||= begin
    new_tc = Hash.new { |h, k| h[k] = {} }
    if @scoped_children.any?
      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)
      all_object_types.each do |t|
        new_tc[t] = get_typed_children(t)
      end
    end
    new_tc
  end
end