File: type_stack.rb

package info (click to toggle)
ruby-graphql-client 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 264 kB
  • sloc: ruby: 2,077; makefile: 4
file content (144 lines) | stat: -rw-r--r-- 4,740 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# frozen_string_literal: true
module GraphQL
  class Client
    module TypeStack
      # @return [GraphQL::Schema] the schema whose types are present in this document
      attr_reader :schema

      # When it enters an object (starting with query or mutation root), it's pushed on this stack.
      # When it exits, it's popped off.
      # @return [Array<GraphQL::ObjectType, GraphQL::Union, GraphQL::Interface>]
      attr_reader :object_types

      # When it enters a field, it's pushed on this stack (useful for nested fields, args).
      # When it exits, it's popped off.
      # @return [Array<GraphQL::Field>] fields which have been entered
      attr_reader :field_definitions

      # Directives are pushed on, then popped off while traversing the tree
      # @return [Array<GraphQL::Node::Directive>] directives which have been entered
      attr_reader :directive_definitions

      # @return [Array<GraphQL::Node::Argument>] arguments which have been entered
      attr_reader :argument_definitions

      # @return [Array<String>] fields which have been entered (by their AST name)
      attr_reader :path

      # @param schema [GraphQL::Schema] the schema whose types to use when climbing this document
      # @param visitor [GraphQL::Language::Visitor] a visitor to follow & watch the types
      def initialize(document, schema:, **rest)
        @schema = schema
        @object_types = []
        @field_definitions = []
        @directive_definitions = []
        @argument_definitions = []
        @path = []
        super(document, **rest)
      end

      def on_directive(node, parent)
        directive_defn = @schema.directives[node.name]
        @directive_definitions.push(directive_defn)
        super(node, parent)
      ensure
        @directive_definitions.pop
      end

      def on_field(node, parent)
        parent_type = @object_types.last
        parent_type = parent_type.unwrap

        field_definition = @schema.get_field(parent_type, node.name)
        @field_definitions.push(field_definition)
        if !field_definition.nil?
          next_object_type = field_definition.type
          @object_types.push(next_object_type)
        else
          @object_types.push(nil)
        end
        @path.push(node.alias || node.name)
        super(node, parent)
      ensure
        @field_definitions.pop
        @object_types.pop
        @path.pop
      end

      def on_argument(node, parent)
        if @argument_definitions.last
          arg_type = @argument_definitions.last.type.unwrap
          if arg_type.kind.input_object?
            argument_defn = arg_type.arguments[node.name]
          else
            argument_defn = nil
          end
        elsif @directive_definitions.last
          argument_defn = @directive_definitions.last.arguments[node.name]
        elsif @field_definitions.last
          argument_defn = @field_definitions.last.arguments[node.name]
        else
          argument_defn = nil
        end
        @argument_definitions.push(argument_defn)
        @path.push(node.name)
        super(node, parent)
      ensure
        @argument_definitions.pop
        @path.pop
      end

      def on_operation_definition(node, parent)
        # eg, QueryType, MutationType
        object_type = @schema.root_type_for_operation(node.operation_type)
        @object_types.push(object_type)
        @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
        super(node, parent)
      ensure
        @object_types.pop
        @path.pop
      end

      def on_inline_fragment(node, parent)
        object_type = if node.type
                        @schema.get_type(node.type.name)
                      else
                        @object_types.last
                      end
        if !object_type.nil?
          object_type = object_type.unwrap
        end
        @object_types.push(object_type)
        @path.push("...#{node.type ? " on #{node.type.to_query_string}" : ""}")
        super(node, parent)
      ensure
        @object_types.pop
        @path.pop
      end

      def on_fragment_definition(node, parent)
        object_type = if node.type
                        @schema.get_type(node.type.name)
                      else
                        @object_types.last
                      end
        if !object_type.nil?
          object_type = object_type.unwrap
        end
        @object_types.push(object_type)
        @path.push("fragment #{node.name}")
        super(node, parent)
      ensure
        @object_types.pop
        @path.pop
      end

      def on_fragment_spread(node, parent)
        @path.push("... #{node.name}")
        super(node, parent)
      ensure
        @path.pop
      end
    end
  end
end