1
1
module GraphQL
2
2
module Language
3
3
module Nodes
4
- # AbstractNode creates classes who:
5
- # - require their keyword arguments, throw ArgumentError if they don't match
6
- # - expose accessors for keyword arguments
4
+ # {AbstractNode} is the base class for all nodes in a GraphQL AST.
5
+ #
6
+ # It provides some APIs for working with ASTs:
7
+ # - `children` returns all AST nodes attached to this one. Used for tree traversal.
8
+ # - `scalars` returns all scalar (Ruby) values attached to this one. Used for comparing nodes.
9
+ # - `to_query_string` turns an AST node into a GraphQL string
7
10
class AbstractNode
8
11
attr_accessor :line , :col
9
12
10
- # @param options [Hash] Must contain all attributes defined by {required_attrs}, may also include `position_source`
13
+ # Initialize a node by extracting its position,
14
+ # then calling the class's `initialize_node` method.
15
+ # @param options [Hash] Initial attributes for this node
11
16
def initialize ( options = { } )
12
17
if options . key? ( :position_source )
13
18
position_source = options . delete ( :position_source )
@@ -25,36 +30,43 @@ def initialize_node(options={})
25
30
raise NotImplementedError
26
31
end
27
32
33
+ # Value equality
34
+ # @return [Boolean] True if `self` is equivalent to `other`
28
35
def eql? ( other )
29
36
return true if equal? ( other )
30
37
other . is_a? ( self . class ) &&
31
38
other . scalars . eql? ( self . scalars ) &&
32
39
other . children . eql? ( self . children )
33
40
end
34
41
35
- # @return [GraphQL::Language::Nodes::AbstractNode] all nodes in the tree below this one
42
+ # @return [Array< GraphQL::Language::Nodes::AbstractNode> ] all nodes in the tree below this one
36
43
def children
37
44
self . class . child_attributes
38
45
. map { |attr_name | public_send ( attr_name ) }
39
46
. flatten
40
47
end
41
48
49
+ # @return [Array<Integer, Float, String, Boolean, Array>] Scalar values attached to this node
42
50
def scalars
43
51
self . class . scalar_attributes
44
52
. map { |attr_name | public_send ( attr_name ) }
45
53
end
46
54
47
55
class << self
56
+ # A node subclass inherits `scalar_attributes`
57
+ # and `child_attributes` from its parent
48
58
def inherited ( subclass )
49
59
subclass . scalar_attributes ( *@scalar_attributes )
50
60
subclass . child_attributes ( *@child_attributes )
51
61
end
52
62
63
+ # define `attr_names` as places where scalars may be attached to this node
53
64
def scalar_attributes ( *attr_names )
54
65
@scalar_attributes ||= [ ]
55
66
@scalar_attributes += attr_names
56
67
end
57
68
69
+ # define `attr_names` as places where child nodes may be attached to this node
58
70
def child_attributes ( *attr_names )
59
71
@child_attributes ||= [ ]
60
72
@child_attributes += attr_names
@@ -70,6 +82,7 @@ def to_query_string
70
82
end
71
83
end
72
84
85
+ # Base class for non-null type names and list type names
73
86
class WrapperType < AbstractNode
74
87
attr_accessor :of_type
75
88
scalar_attributes :of_type
@@ -83,6 +96,7 @@ def children
83
96
end
84
97
end
85
98
99
+ # Base class for nodes whose only value is a name (no child nodes or other scalars)
86
100
class NameOnlyNode < AbstractNode
87
101
attr_accessor :name
88
102
scalar_attributes :name
@@ -96,11 +110,17 @@ def children
96
110
end
97
111
end
98
112
99
-
113
+ # A key-value pair for a field's inputs
100
114
class Argument < AbstractNode
101
115
attr_accessor :name , :value
102
116
scalar_attributes :name , :value
103
117
118
+ # @!attribute name
119
+ # @return [String] the key for this argument
120
+
121
+ # @!attribute value
122
+ # @return [String, Float, Integer, Boolean, Array, InputObject] The value passed for this key
123
+
104
124
def initialize_node ( name : nil , value : nil )
105
125
@name = name
106
126
@value = value
@@ -122,22 +142,38 @@ def initialize_node(name: nil, arguments: [])
122
142
end
123
143
end
124
144
145
+ # This is the AST root for normal queries
146
+ #
147
+ # @example Deriving a document by parsing a string
148
+ # document = GraphQL.parse(query_string)
149
+ #
150
+ # @example Creating a string from a document
151
+ # document.to_query_string
152
+ # # { ... }
153
+ #
125
154
class Document < AbstractNode
126
155
attr_accessor :definitions
127
156
child_attributes :definitions
128
157
158
+ # @!attribute definitions
159
+ # @return [Array<OperationDefinition, FragmentDefinition>] top-level GraphQL units: operations or fragments
129
160
def initialize_node ( definitions : [ ] )
130
161
@definitions = definitions
131
162
end
132
163
end
133
164
165
+ # An enum value. The string is available as {#name}.
134
166
class Enum < NameOnlyNode ; end
135
167
168
+ # A single selection in a GraphQL query.
136
169
class Field < AbstractNode
137
170
attr_accessor :name , :alias , :arguments , :directives , :selections
138
171
scalar_attributes :name , :alias
139
172
child_attributes :arguments , :directives , :selections
140
173
174
+ # @!attribute selections
175
+ # @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field)
176
+
141
177
def initialize_node ( name : nil , arguments : [ ] , directives : [ ] , selections : [ ] , **kwargs )
142
178
@name = name
143
179
# oops, alias is a keyword:
@@ -148,11 +184,17 @@ def initialize_node(name: nil, arguments: [], directives: [], selections: [], **
148
184
end
149
185
end
150
186
187
+ # A reusable fragment, defined at document-level.
151
188
class FragmentDefinition < AbstractNode
152
189
attr_accessor :name , :type , :directives , :selections
153
190
scalar_attributes :name , :type
154
191
child_attributes :directives , :selections
155
192
193
+ # @!attribute name
194
+ # @return [String] the identifier for this fragment, which may be applied with `...#{name}`
195
+
196
+ # @!attribute type
197
+ # @return [String] the type condition for this fragment (name of type which it may apply to)
156
198
def initialize_node ( name : nil , type : nil , directives : [ ] , selections : [ ] )
157
199
@name = name
158
200
@type = type
@@ -161,37 +203,50 @@ def initialize_node(name: nil, type: nil, directives: [], selections: [])
161
203
end
162
204
end
163
205
206
+ # Application of a named fragment in a selection
164
207
class FragmentSpread < AbstractNode
165
208
attr_accessor :name , :directives
166
209
scalar_attributes :name
167
210
child_attributes :directives
168
211
212
+ # @!attribute name
213
+ # @return [String] The identifier of the fragment to apply, corresponds with {FragmentDefinition#name}
214
+
169
215
def initialize_node ( name : nil , directives : [ ] )
170
216
@name = name
171
217
@directives = directives
172
218
end
173
219
end
174
220
221
+ # An unnamed fragment, defined directly in the query with `... { }`
175
222
class InlineFragment < AbstractNode
176
223
attr_accessor :type , :directives , :selections
177
224
scalar_attributes :type
178
225
child_attributes :directives , :selections
179
226
227
+ # @!attribute type
228
+ # @return [String, nil] Name of the type this fragment applies to, or `nil` if this fragment applies to any type
229
+
180
230
def initialize_node ( type : nil , directives : [ ] , selections : [ ] )
181
231
@type = type
182
232
@directives = directives
183
233
@selections = selections
184
234
end
185
235
end
186
236
237
+ # A collection of key-value inputs which may be a field argument
187
238
class InputObject < AbstractNode
188
239
attr_accessor :arguments
189
240
child_attributes :arguments
190
241
242
+ # @!attribute arguments
243
+ # @return [Array<Nodes::Argument>] A list of key-value pairs inside this input object
244
+
191
245
def initialize_node ( arguments : [ ] )
192
246
@arguments = arguments
193
247
end
194
248
249
+ # @return [Hash<String, Any>] Recursively turn this input object into a Ruby Hash
195
250
def to_h ( options = { } )
196
251
arguments . inject ( { } ) do |memo , pair |
197
252
v = pair . value
@@ -202,15 +257,32 @@ def to_h(options={})
202
257
end
203
258
204
259
205
-
260
+ # A list type definition, denoted with `[...]` (used for variable type definitions)
206
261
class ListType < WrapperType ; end
262
+
263
+ # A non-null type definition, denoted with `...!` (used for variable type definitions)
207
264
class NonNullType < WrapperType ; end
208
265
266
+ # A query, mutation or subscription.
267
+ # May be anonymous or named.
268
+ # May be explicitly typed (eg `mutation { ... }`) or implicitly a query (eg `{ ... }`).
209
269
class OperationDefinition < AbstractNode
210
270
attr_accessor :operation_type , :name , :variables , :directives , :selections
211
271
scalar_attributes :operation_type , :name
212
272
child_attributes :variables , :directives , :selections
213
273
274
+ # @!attribute variables
275
+ # @return [Array<VariableDefinition>] Variable definitions for this operation
276
+
277
+ # @!attribute selections
278
+ # @return [Array<Field>] Root-level fields on this operation
279
+
280
+ # @!attribute operation_type
281
+ # @return [String, nil] The root type for this operation, or `nil` for implicit `"query"`
282
+
283
+ # @!attribute name
284
+ # @return [String, nil] The name for this operation, or `nil` if unnamed
285
+
214
286
def initialize_node ( operation_type : nil , name : nil , variables : [ ] , directives : [ ] , selections : [ ] )
215
287
@operation_type = operation_type
216
288
@name = name
@@ -220,22 +292,33 @@ def initialize_node(operation_type: nil, name: nil, variables: [], directives: [
220
292
end
221
293
end
222
294
295
+ # A type name, used for variable definitions
223
296
class TypeName < NameOnlyNode ; end
224
297
298
+ # An operation-level query variable
225
299
class VariableDefinition < AbstractNode
226
300
attr_accessor :name , :type , :default_value
227
301
scalar_attributes :name , :type , :default_value
228
302
303
+ # @!attribute default_value
304
+ # @return [String, Integer, Float, Boolean, Array] A Ruby value to use if no other value is provided
305
+
306
+ # @!attribute type
307
+ # @return [TypeName, NonNullType, ListType] The expected type of this value
308
+
309
+ # @!attribute name
310
+ # @return [String] The identifier for this variable, _without_ `$`
311
+
229
312
def initialize_node ( name : nil , type : nil , default_value : nil )
230
313
@name = name
231
314
@type = type
232
315
@default_value = default_value
233
316
end
234
317
end
235
318
319
+ # Usage of a variable in a query. Name does _not_ include `$`.
236
320
class VariableIdentifier < NameOnlyNode ; end
237
321
238
-
239
322
class SchemaDefinition < AbstractNode
240
323
attr_accessor :query , :mutation , :subscription
241
324
scalar_attributes :query , :mutation , :subscription
0 commit comments