graphql 0.18.14 → 0.18.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/query_complexity.rb +15 -6
- data/lib/graphql/analysis/query_depth.rb +11 -10
- data/lib/graphql/directive.rb +2 -6
- data/lib/graphql/directive/include_directive.rb +0 -4
- data/lib/graphql/directive/skip_directive.rb +0 -4
- data/lib/graphql/execution/directive_checks.rb +22 -13
- data/lib/graphql/execution_error.rb +7 -0
- data/lib/graphql/internal_representation/node.rb +20 -2
- data/lib/graphql/internal_representation/rewrite.rb +66 -20
- data/lib/graphql/language/generation.rb +22 -8
- data/lib/graphql/language/nodes.rb +48 -20
- data/lib/graphql/language/parser.rb +436 -423
- data/lib/graphql/language/parser.y +22 -19
- data/lib/graphql/language/parser_tests.rb +131 -2
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -0
- data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
- data/lib/graphql/query/serial_execution/value_resolution.rb +4 -1
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/static_validation/message.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +10 -12
- data/spec/graphql/directive_spec.rb +139 -1
- data/spec/graphql/execution_error_spec.rb +63 -3
- data/spec/graphql/introspection/type_type_spec.rb +2 -0
- data/spec/graphql/language/generation_spec.rb +55 -7
- data/spec/graphql/query/executor_spec.rb +4 -2
- data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
- data/spec/graphql/schema/printer_spec.rb +1 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +6 -6
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
- data/spec/graphql/static_validation/validator_spec.rb +1 -1
- data/spec/support/dairy_app.rb +8 -0
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca81d77891fe081da31667ba3d1a8676ff489ff5
|
4
|
+
data.tar.gz: e2b4a12d439ce76943470264e60d6007ae7f61fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d18944b50b350786c710bc9e9ca3f9e463ccc8a6d835fa3b24e2442120e4b41280828ec59ad4e916b5aa3bea5f0566b9fb9bb6a462eaa75dcc7397d9099f5892
|
7
|
+
data.tar.gz: 78b22a36ffbed73b1b512c8b351cc55f99a8484139ac71fd1f8f4dc2a9f7682b68c681e5a16d8b7776500b24cd721ac576519566dae87c0bb94c97536651eca6
|
@@ -18,10 +18,13 @@ module GraphQL
|
|
18
18
|
# State for the query complexity calcuation:
|
19
19
|
# - `query` is needed for variables, then passed to handler
|
20
20
|
# - `complexities_on_type` holds complexity scores for each type in an IRep node
|
21
|
+
# - `skip_depth` increments for each skipped node, then decrements on the way out.
|
22
|
+
# While it's greater than `0`, we're visiting a skipped part of the query.
|
21
23
|
def initial_value(query)
|
22
24
|
{
|
23
25
|
query: query,
|
24
26
|
complexities_on_type: [TypeComplexity.new],
|
27
|
+
skip_depth: 0,
|
25
28
|
}
|
26
29
|
end
|
27
30
|
|
@@ -29,16 +32,22 @@ module GraphQL
|
|
29
32
|
def call(memo, visit_type, irep_node)
|
30
33
|
if irep_node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
|
31
34
|
if visit_type == :enter
|
32
|
-
|
35
|
+
if irep_node.skipped?
|
36
|
+
memo[:skip_depth] += 1
|
37
|
+
elsif memo[:skip_depth] == 0
|
38
|
+
memo[:complexities_on_type].push(TypeComplexity.new)
|
39
|
+
end
|
33
40
|
else
|
34
|
-
|
35
|
-
|
36
|
-
|
41
|
+
if memo[:skip_depth] > 0
|
42
|
+
if irep_node.skipped?
|
43
|
+
memo[:skip_depth] -= 1
|
44
|
+
end
|
37
45
|
else
|
46
|
+
type_complexities = memo[:complexities_on_type].pop
|
38
47
|
child_complexity = type_complexities.max_possible_complexity
|
39
|
-
get_complexity(irep_node, memo[:query], child_complexity)
|
48
|
+
own_complexity = get_complexity(irep_node, memo[:query], child_complexity)
|
49
|
+
memo[:complexities_on_type].last.merge(irep_node.definitions, own_complexity)
|
40
50
|
end
|
41
|
-
memo[:complexities_on_type].last.merge(irep_node.definitions, own_complexity)
|
42
51
|
end
|
43
52
|
end
|
44
53
|
memo
|
@@ -16,26 +16,27 @@ module GraphQL
|
|
16
16
|
{
|
17
17
|
max_depth: 0,
|
18
18
|
current_depth: 0,
|
19
|
-
|
19
|
+
skip_depth: 0,
|
20
20
|
query: query,
|
21
21
|
}
|
22
22
|
end
|
23
23
|
|
24
24
|
def call(memo, visit_type, irep_node)
|
25
25
|
if irep_node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
|
26
|
+
# Don't validate introspection fields or skipped nodes
|
27
|
+
not_validated_node = GraphQL::Schema::DYNAMIC_FIELDS.include?(irep_node.definition_name) || !irep_node.included?
|
26
28
|
if visit_type == :enter
|
27
|
-
if
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
elsif GraphQL::Execution::DirectiveChecks.include?(irep_node, memo[:query])
|
29
|
+
if not_validated_node
|
30
|
+
memo[:skip_depth] += 1
|
31
|
+
elsif memo[:skip_depth] > 0
|
32
|
+
# we're inside an introspection query or skipped node
|
33
|
+
else
|
33
34
|
memo[:current_depth] += 1
|
34
35
|
end
|
35
36
|
else
|
36
|
-
if
|
37
|
-
memo[:
|
38
|
-
|
37
|
+
if not_validated_node
|
38
|
+
memo[:skip_depth] -= 1
|
39
|
+
else
|
39
40
|
if memo[:max_depth] < memo[:current_depth]
|
40
41
|
memo[:max_depth] = memo[:current_depth]
|
41
42
|
end
|
data/lib/graphql/directive.rb
CHANGED
@@ -7,9 +7,9 @@ module GraphQL
|
|
7
7
|
#
|
8
8
|
class Directive
|
9
9
|
include GraphQL::Define::InstanceDefinable
|
10
|
-
accepts_definitions :locations, :name, :description,
|
10
|
+
accepts_definitions :locations, :name, :description, argument: GraphQL::Define::AssignArgument
|
11
11
|
|
12
|
-
lazy_defined_attr_accessor :locations, :arguments, :name, :description
|
12
|
+
lazy_defined_attr_accessor :locations, :arguments, :name, :description
|
13
13
|
|
14
14
|
LOCATIONS = [
|
15
15
|
QUERY = :QUERY,
|
@@ -25,10 +25,6 @@ module GraphQL
|
|
25
25
|
@arguments = {}
|
26
26
|
end
|
27
27
|
|
28
|
-
def include?(arguments)
|
29
|
-
include_proc.call(arguments)
|
30
|
-
end
|
31
|
-
|
32
28
|
def to_s
|
33
29
|
"<GraphQL::Directive #{name}>"
|
34
30
|
end
|
@@ -3,8 +3,4 @@ GraphQL::Directive::IncludeDirective = GraphQL::Directive.define do
|
|
3
3
|
description "Include this part of the query if `if` is true"
|
4
4
|
locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
|
5
5
|
argument :if, !GraphQL::BOOLEAN_TYPE
|
6
|
-
|
7
|
-
include_proc -> (arguments) {
|
8
|
-
arguments["if"]
|
9
|
-
}
|
10
6
|
end
|
@@ -4,8 +4,4 @@ GraphQL::Directive::SkipDirective = GraphQL::Directive.define do
|
|
4
4
|
locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
|
5
5
|
|
6
6
|
argument :if, !GraphQL::BOOLEAN_TYPE
|
7
|
-
|
8
|
-
include_proc -> (arguments) {
|
9
|
-
!arguments["if"]
|
10
|
-
}
|
11
7
|
end
|
@@ -10,22 +10,31 @@ module GraphQL
|
|
10
10
|
|
11
11
|
# This covers `@include(if:)` & `@skip(if:)`
|
12
12
|
# @return [Boolean] Should this node be skipped altogether?
|
13
|
-
def skip?(
|
14
|
-
|
15
|
-
if directive_node.name == SKIP || directive_node.name == INCLUDE
|
16
|
-
directive_defn = directive_node.definitions.first
|
17
|
-
args = query.arguments_for(directive_node, directive_defn)
|
18
|
-
if !directive_defn.include?(args)
|
19
|
-
return true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
false
|
13
|
+
def skip?(ast_node, query)
|
14
|
+
!include?(ast_node, query)
|
24
15
|
end
|
25
16
|
|
26
17
|
# @return [Boolean] Should this node be included in the query?
|
27
|
-
def include?(
|
28
|
-
|
18
|
+
def include?(directive_irep_nodes, query)
|
19
|
+
directive_irep_nodes.each do |directive_irep_node|
|
20
|
+
name = directive_irep_node.name
|
21
|
+
directive_defn = query.schema.directives[name]
|
22
|
+
case name
|
23
|
+
when SKIP
|
24
|
+
args = query.arguments_for(directive_irep_node, directive_defn)
|
25
|
+
if args['if'] == true
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
when INCLUDE
|
29
|
+
args = query.arguments_for(directive_irep_node, directive_defn)
|
30
|
+
if args['if'] == false
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
else
|
34
|
+
# Undefined directive, or one we don't care about
|
35
|
+
end
|
36
|
+
end
|
37
|
+
true
|
29
38
|
end
|
30
39
|
end
|
31
40
|
end
|
@@ -6,6 +6,10 @@ module GraphQL
|
|
6
6
|
# @return [GraphQL::Language::Nodes::Field] the field where the error occured
|
7
7
|
attr_accessor :ast_node
|
8
8
|
|
9
|
+
# @return [String] an array describing the JSON-path into the execution
|
10
|
+
# response which corresponds to this error.
|
11
|
+
attr_accessor :path
|
12
|
+
|
9
13
|
def initialize(message, ast_node: nil)
|
10
14
|
@ast_node = ast_node
|
11
15
|
super(message)
|
@@ -24,6 +28,9 @@ module GraphQL
|
|
24
28
|
}
|
25
29
|
]
|
26
30
|
end
|
31
|
+
if path
|
32
|
+
hash["path"] = path
|
33
|
+
end
|
27
34
|
hash
|
28
35
|
end
|
29
36
|
end
|
@@ -3,7 +3,7 @@ require "set"
|
|
3
3
|
module GraphQL
|
4
4
|
module InternalRepresentation
|
5
5
|
class Node
|
6
|
-
def initialize(parent:, ast_node: nil, return_type: nil, name: nil, definition_name: nil, definitions: {}, children: {}, spreads: [], directives: Set.new)
|
6
|
+
def initialize(parent:, ast_node: nil, return_type: nil, name: nil, definition_name: nil, definitions: {}, children: {}, spreads: [], directives: Set.new, included: true)
|
7
7
|
# Make sure these are kept in sync with #dup
|
8
8
|
@ast_node = ast_node
|
9
9
|
@return_type = return_type
|
@@ -14,6 +14,7 @@ module GraphQL
|
|
14
14
|
@children = children
|
15
15
|
@spreads = spreads
|
16
16
|
@directives = directives
|
17
|
+
@included = included
|
17
18
|
end
|
18
19
|
|
19
20
|
# Note: by the time this gets out of the Rewrite phase, this will be empty -- it's emptied out when fragments are merged back in
|
@@ -58,6 +59,14 @@ module GraphQL
|
|
58
59
|
# @return [Array<GraphQL::Query::Node>]
|
59
60
|
attr_reader :children
|
60
61
|
|
62
|
+
# @return [Boolean] false if every field for this node included `@skip(if: true)`
|
63
|
+
attr_accessor :included
|
64
|
+
alias :included? :included
|
65
|
+
|
66
|
+
def skipped?
|
67
|
+
!@included
|
68
|
+
end
|
69
|
+
|
61
70
|
# @return [GraphQL::InternalRepresentation::Node] The node which this node is a child of
|
62
71
|
attr_reader :parent
|
63
72
|
|
@@ -72,9 +81,18 @@ module GraphQL
|
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
84
|
+
def path
|
85
|
+
path = parent ? parent.path : []
|
86
|
+
path << name if name
|
87
|
+
path << @index if @index
|
88
|
+
path
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_writer :index
|
92
|
+
|
75
93
|
def inspect(indent = 0)
|
76
94
|
own_indent = " " * indent
|
77
|
-
self_inspect = "#{own_indent}<Node #{name} (#{definition_name}: {#{definitions.keys.join("|")}} -> #{return_type})>"
|
95
|
+
self_inspect = "#{own_indent}<Node #{name} #{skipped? ? "(skipped)" : ""}(#{definition_name}: {#{definitions.keys.join("|")}} -> #{return_type})>"
|
78
96
|
if children.any?
|
79
97
|
self_inspect << " {\n#{children.values.map { |n| n.inspect(indent + 2)}.join("\n")}\n#{own_indent}}"
|
80
98
|
end
|
@@ -24,7 +24,7 @@ module GraphQL
|
|
24
24
|
# This tracks dependencies from fragment to Node where it was used
|
25
25
|
# { frag_name => [dependent_node, dependent_node]}
|
26
26
|
@fragment_spreads = Hash.new { |h, k| h[k] = []}
|
27
|
-
# [Nodes::Directive ...
|
27
|
+
# [[Nodes::Directive ...]] directive affecting the current scope
|
28
28
|
@parent_directives = []
|
29
29
|
end
|
30
30
|
|
@@ -55,6 +55,7 @@ module GraphQL
|
|
55
55
|
name: node_name,
|
56
56
|
definition_name: ast_node.name,
|
57
57
|
parent: parent_node,
|
58
|
+
included: false, # may be set to true on leaving the node
|
58
59
|
)
|
59
60
|
end
|
60
61
|
object_type = context.parent_type_definition.unwrap
|
@@ -64,20 +65,21 @@ module GraphQL
|
|
64
65
|
}
|
65
66
|
|
66
67
|
visitor[Nodes::InlineFragment].enter << -> (ast_node, prev_ast_node) {
|
67
|
-
@parent_directives.push(
|
68
|
+
@parent_directives.push(InlineFragmentDirectives.new)
|
68
69
|
}
|
69
70
|
|
70
71
|
visitor[Nodes::Directive].enter << -> (ast_node, prev_ast_node) {
|
71
72
|
# It could be a query error where a directive is somewhere it shouldn't be
|
72
73
|
if @parent_directives.any?
|
73
|
-
|
74
|
+
directive_irep_node = Node.new(
|
74
75
|
name: ast_node.name,
|
75
76
|
definition_name: ast_node.name,
|
76
77
|
ast_node: ast_node,
|
77
|
-
definitions:
|
78
|
+
definitions: {context.directive_definition => context.directive_definition},
|
78
79
|
# This isn't used, the directive may have many parents in the case of inline fragment
|
79
80
|
parent: nil,
|
80
81
|
)
|
82
|
+
@parent_directives.last.push(directive_irep_node)
|
81
83
|
end
|
82
84
|
}
|
83
85
|
|
@@ -88,6 +90,7 @@ module GraphQL
|
|
88
90
|
parent: parent_node,
|
89
91
|
name: ast_node.name,
|
90
92
|
ast_node: ast_node,
|
93
|
+
included: false, # this may be set to true on leaving the node
|
91
94
|
)
|
92
95
|
# The parent node has a reference to the fragment
|
93
96
|
parent_node.spreads.push(spread_node)
|
@@ -117,8 +120,9 @@ module GraphQL
|
|
117
120
|
# so that they can be applied to fields when
|
118
121
|
# the fragment is merged in later
|
119
122
|
spread_node = @nodes.pop
|
120
|
-
|
121
|
-
|
123
|
+
applicable_directives = pop_applicable_directives(@parent_directives)
|
124
|
+
spread_node.included ||= GraphQL::Execution::DirectiveChecks.include?(applicable_directives, context.query)
|
125
|
+
spread_node.directives.merge(applicable_directives)
|
122
126
|
}
|
123
127
|
|
124
128
|
visitor[Nodes::FragmentDefinition].leave << -> (ast_node, prev_ast_node) {
|
@@ -139,8 +143,9 @@ module GraphQL
|
|
139
143
|
# and record any directives that were visited
|
140
144
|
# during this field & before it (eg, inline fragments)
|
141
145
|
field_node = @nodes.pop
|
142
|
-
|
143
|
-
|
146
|
+
applicable_directives = pop_applicable_directives(@parent_directives)
|
147
|
+
field_node.directives.merge(applicable_directives)
|
148
|
+
field_node.included ||= GraphQL::Execution::DirectiveChecks.include?(applicable_directives, context.query)
|
144
149
|
}
|
145
150
|
|
146
151
|
visitor[Nodes::Document].leave << -> (ast_node, prev_ast_node) {
|
@@ -149,12 +154,14 @@ module GraphQL
|
|
149
154
|
while fragment_node = @independent_fragments.pop
|
150
155
|
fragment_usages = @fragment_spreads[fragment_node.name]
|
151
156
|
while dependent_node = fragment_usages.pop
|
152
|
-
#
|
153
|
-
|
154
|
-
|
157
|
+
# Find the spreads for this reference
|
158
|
+
resolved_spread_nodes = dependent_node.spreads.select { |spr| spr.name == fragment_node.name }
|
159
|
+
spread_is_included = resolved_spread_nodes.any?(&:included?)
|
160
|
+
# Since we're going to resolve them, remove them from the dependcies
|
161
|
+
resolved_spread_nodes.each { |r_node| dependent_node.spreads.delete(r_node) }
|
155
162
|
|
156
163
|
# resolve the dependency (merge into dependent node)
|
157
|
-
deep_merge(dependent_node, fragment_node,
|
164
|
+
deep_merge(dependent_node, fragment_node, spread_is_included)
|
158
165
|
owner = dependent_node.owner
|
159
166
|
if owner.ast_node.is_a?(Nodes::FragmentDefinition) && !any_fragment_spreads?(owner)
|
160
167
|
@independent_fragments.push(owner)
|
@@ -166,27 +173,66 @@ module GraphQL
|
|
166
173
|
|
167
174
|
private
|
168
175
|
|
169
|
-
# Merge the
|
170
|
-
|
176
|
+
# Merge the children from `fragment_node` into `parent_node`.
|
177
|
+
# This is an implementation of "fragment inlining"
|
178
|
+
def deep_merge(parent_node, fragment_node, included)
|
171
179
|
fragment_node.children.each do |name, child_node|
|
172
|
-
deep_merge_child(parent_node, name, child_node,
|
180
|
+
deep_merge_child(parent_node, name, child_node, included)
|
173
181
|
end
|
174
182
|
end
|
175
183
|
|
176
|
-
# Merge `node` into `parent_node`'s children, as `name`, applying `
|
177
|
-
|
178
|
-
|
184
|
+
# Merge `node` into `parent_node`'s children, as `name`, applying `extra_included`
|
185
|
+
# `extra_included` comes from the spread node:
|
186
|
+
# - If the spread was included, first-level children should be included if _either_ node was included
|
187
|
+
# - If the spread was _not_ included, first-level children should be included if _a pre-existing_ node was included
|
188
|
+
# (A copied node should be excluded)
|
189
|
+
def deep_merge_child(parent_node, name, node, extra_included)
|
190
|
+
child_node = parent_node.children[name]
|
191
|
+
previously_included = child_node.nil? ? false : child_node.included?
|
192
|
+
next_included = extra_included ? (previously_included || node.included?) : previously_included
|
193
|
+
|
194
|
+
if child_node.nil?
|
195
|
+
child_node = parent_node.children[name] = node.dup
|
196
|
+
end
|
197
|
+
|
179
198
|
child_node.definitions.merge!(node.definitions)
|
199
|
+
|
200
|
+
child_node.included = next_included
|
201
|
+
|
202
|
+
|
203
|
+
|
180
204
|
node.children.each do |merge_child_name, merge_child_node|
|
181
|
-
deep_merge_child(child_node, merge_child_name, merge_child_node,
|
205
|
+
deep_merge_child(child_node, merge_child_name, merge_child_node, node.included)
|
182
206
|
end
|
183
|
-
child_node.directives.merge(extra_directives)
|
184
207
|
end
|
185
208
|
|
186
209
|
# return true if node or _any_ children have a fragment spread
|
187
210
|
def any_fragment_spreads?(node)
|
188
211
|
node.spreads.any? || node.children.any? { |name, node| any_fragment_spreads?(node) }
|
189
212
|
end
|
213
|
+
|
214
|
+
# pop off own directives,
|
215
|
+
# then check the last one to see if it's directives
|
216
|
+
# from an inline fragment. If it is, add them in
|
217
|
+
# @return [Array<Node>]
|
218
|
+
def pop_applicable_directives(directive_stack)
|
219
|
+
own_directives = directive_stack.pop
|
220
|
+
if directive_stack.last.is_a?(InlineFragmentDirectives)
|
221
|
+
own_directives = directive_stack.last + own_directives
|
222
|
+
end
|
223
|
+
own_directives
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
# It's an array, but can be identified with `is_a?`
|
228
|
+
class InlineFragmentDirectives
|
229
|
+
extend Forwardable
|
230
|
+
def initialize
|
231
|
+
@storage = []
|
232
|
+
end
|
233
|
+
|
234
|
+
def_delegators :@storage, :push, :+
|
235
|
+
end
|
190
236
|
end
|
191
237
|
end
|
192
238
|
end
|
@@ -21,7 +21,9 @@ module GraphQL
|
|
21
21
|
when Nodes::Argument
|
22
22
|
"#{node.name}: #{generate(node.value)}"
|
23
23
|
when Nodes::Directive
|
24
|
-
"@#{node.name}
|
24
|
+
out = "@#{node.name}"
|
25
|
+
out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
|
26
|
+
out
|
25
27
|
when Nodes::Enum
|
26
28
|
"#{node.name}"
|
27
29
|
when Nodes::Field
|
@@ -77,34 +79,46 @@ module GraphQL
|
|
77
79
|
out << " subscription: #{node.subscription}\n" if node.subscription
|
78
80
|
out << "}"
|
79
81
|
when Nodes::ScalarTypeDefinition
|
80
|
-
"scalar #{node.name}"
|
82
|
+
out = "scalar #{node.name}"
|
83
|
+
out << generate_directives(node.directives)
|
81
84
|
when Nodes::ObjectTypeDefinition
|
82
85
|
out = "type #{node.name}"
|
86
|
+
out << generate_directives(node.directives)
|
83
87
|
out << " implements " << node.interfaces.join(", ") unless node.interfaces.empty?
|
84
88
|
out << generate_field_definitions(node.fields)
|
85
89
|
when Nodes::InputValueDefinition
|
86
90
|
out = "#{node.name}: #{generate(node.type)}"
|
87
91
|
out << " = #{generate(node.default_value)}" unless node.default_value.nil?
|
88
|
-
out
|
92
|
+
out << generate_directives(node.directives)
|
89
93
|
when Nodes::FieldDefinition
|
90
94
|
out = node.name.dup
|
91
95
|
unless node.arguments.empty?
|
92
96
|
out << "(" << node.arguments.map{ |arg| generate(arg) }.join(", ") << ")"
|
93
97
|
end
|
94
98
|
out << ": #{generate(node.type)}"
|
99
|
+
out << generate_directives(node.directives)
|
95
100
|
when Nodes::InterfaceTypeDefinition
|
96
101
|
out = "interface #{node.name}"
|
102
|
+
out << generate_directives(node.directives)
|
97
103
|
out << generate_field_definitions(node.fields)
|
98
104
|
when Nodes::UnionTypeDefinition
|
99
|
-
"union #{node.name}
|
105
|
+
out = "union #{node.name}"
|
106
|
+
out << generate_directives(node.directives)
|
107
|
+
out << " = " + node.types.join(" | ")
|
100
108
|
when Nodes::EnumTypeDefinition
|
101
|
-
out = "enum #{node.name} {\n"
|
109
|
+
out = "enum #{node.name}#{generate_directives(node.directives)} {\n"
|
102
110
|
node.values.each do |value|
|
103
|
-
out <<
|
111
|
+
out << generate(value)
|
104
112
|
end
|
105
113
|
out << "}"
|
114
|
+
when Nodes::EnumValueDefinition
|
115
|
+
out = " #{node.name}"
|
116
|
+
out << generate_directives(node.directives)
|
117
|
+
out << "\n"
|
106
118
|
when Nodes::InputObjectTypeDefinition
|
107
|
-
out = "input #{node.name}
|
119
|
+
out = "input #{node.name}"
|
120
|
+
out << generate_directives(node.directives)
|
121
|
+
out << " {\n"
|
108
122
|
node.fields.each do |field|
|
109
123
|
out << " #{generate(field)}\n"
|
110
124
|
end
|
@@ -116,7 +130,7 @@ module GraphQL
|
|
116
130
|
when Array
|
117
131
|
"[#{node.map { |v| generate(v) }.join(", ")}]"
|
118
132
|
when Hash
|
119
|
-
"{
|
133
|
+
"{#{node.map { |k, v| "#{k}: #{generate(v)}" }.join(", ")}}"
|
120
134
|
else
|
121
135
|
raise TypeError
|
122
136
|
end
|