graphql 1.7.14 → 1.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/loader_generator.rb +1 -1
  4. data/lib/generators/graphql/mutation_generator.rb +1 -6
  5. data/lib/generators/graphql/templates/function.erb +2 -2
  6. data/lib/generators/graphql/templates/loader.erb +2 -2
  7. data/lib/graphql.rb +2 -0
  8. data/lib/graphql/argument.rb +0 -1
  9. data/lib/graphql/backwards_compatibility.rb +2 -3
  10. data/lib/graphql/base_type.rb +18 -16
  11. data/lib/graphql/compatibility/query_parser_specification.rb +0 -117
  12. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -14
  13. data/lib/graphql/define/assign_object_field.rb +5 -12
  14. data/lib/graphql/deprecated_dsl.rb +28 -0
  15. data/lib/graphql/directive.rb +0 -1
  16. data/lib/graphql/enum_type.rb +1 -3
  17. data/lib/graphql/execution.rb +0 -1
  18. data/lib/graphql/execution/multiplex.rb +29 -12
  19. data/lib/graphql/field.rb +5 -20
  20. data/lib/graphql/function.rb +12 -0
  21. data/lib/graphql/input_object_type.rb +1 -3
  22. data/lib/graphql/internal_representation/node.rb +14 -26
  23. data/lib/graphql/internal_representation/visit.rb +6 -3
  24. data/lib/graphql/introspection/arguments_field.rb +0 -1
  25. data/lib/graphql/introspection/enum_values_field.rb +0 -1
  26. data/lib/graphql/introspection/fields_field.rb +0 -1
  27. data/lib/graphql/introspection/input_fields_field.rb +0 -1
  28. data/lib/graphql/introspection/interfaces_field.rb +0 -1
  29. data/lib/graphql/introspection/of_type_field.rb +0 -1
  30. data/lib/graphql/introspection/possible_types_field.rb +0 -1
  31. data/lib/graphql/introspection/schema_field.rb +0 -1
  32. data/lib/graphql/introspection/type_by_name_field.rb +0 -1
  33. data/lib/graphql/introspection/typename_field.rb +0 -1
  34. data/lib/graphql/language.rb +0 -3
  35. data/lib/graphql/language/generation.rb +182 -3
  36. data/lib/graphql/language/lexer.rb +69 -144
  37. data/lib/graphql/language/lexer.rl +4 -15
  38. data/lib/graphql/language/nodes.rb +76 -136
  39. data/lib/graphql/language/parser.rb +621 -668
  40. data/lib/graphql/language/parser.y +11 -17
  41. data/lib/graphql/language/token.rb +3 -10
  42. data/lib/graphql/object_type.rb +6 -1
  43. data/lib/graphql/query.rb +13 -8
  44. data/lib/graphql/query/arguments.rb +33 -48
  45. data/lib/graphql/query/context.rb +1 -0
  46. data/lib/graphql/query/literal_input.rb +1 -4
  47. data/lib/graphql/relay/connection_resolve.rb +3 -0
  48. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  49. data/lib/graphql/relay/relation_connection.rb +19 -14
  50. data/lib/graphql/schema.rb +219 -12
  51. data/lib/graphql/schema/argument.rb +33 -0
  52. data/lib/graphql/schema/build_from_definition.rb +18 -64
  53. data/lib/graphql/schema/enum.rb +76 -0
  54. data/lib/graphql/schema/field.rb +127 -0
  55. data/lib/graphql/schema/field/dynamic_resolve.rb +63 -0
  56. data/lib/graphql/schema/field/unwrapped_resolve.rb +20 -0
  57. data/lib/graphql/schema/input_object.rb +61 -0
  58. data/lib/graphql/schema/interface.rb +32 -0
  59. data/lib/graphql/schema/loader.rb +2 -2
  60. data/lib/graphql/schema/member.rb +97 -0
  61. data/lib/graphql/schema/member/build_type.rb +106 -0
  62. data/lib/graphql/schema/member/has_fields.rb +56 -0
  63. data/lib/graphql/schema/member/instrumentation.rb +113 -0
  64. data/lib/graphql/schema/member/list_type_proxy.rb +21 -0
  65. data/lib/graphql/schema/member/non_null_type_proxy.rb +21 -0
  66. data/lib/graphql/schema/object.rb +65 -0
  67. data/lib/graphql/schema/printer.rb +266 -33
  68. data/lib/graphql/schema/scalar.rb +25 -0
  69. data/lib/graphql/schema/traversal.rb +26 -17
  70. data/lib/graphql/schema/union.rb +48 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -5
  72. data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -15
  73. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -11
  74. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -7
  75. data/lib/graphql/tracing.rb +0 -1
  76. data/lib/graphql/tracing/platform_tracing.rb +7 -20
  77. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  78. data/lib/graphql/unresolved_type_error.rb +2 -3
  79. data/lib/graphql/version.rb +1 -1
  80. data/readme.md +1 -1
  81. data/spec/dummy/app/channels/graphql_channel.rb +1 -22
  82. data/spec/dummy/log/development.log +0 -239
  83. data/spec/dummy/log/test.log +0 -204
  84. data/spec/dummy/test/system/action_cable_subscription_test.rb +0 -4
  85. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  86. data/spec/generators/graphql/function_generator_spec.rb +0 -26
  87. data/spec/generators/graphql/loader_generator_spec.rb +0 -24
  88. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  89. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  90. data/spec/graphql/backtrace_spec.rb +0 -10
  91. data/spec/graphql/base_type_spec.rb +5 -19
  92. data/spec/graphql/boolean_type_spec.rb +3 -3
  93. data/spec/graphql/directive_spec.rb +1 -3
  94. data/spec/graphql/enum_type_spec.rb +5 -18
  95. data/spec/graphql/execution/execute_spec.rb +1 -1
  96. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  97. data/spec/graphql/float_type_spec.rb +2 -2
  98. data/spec/graphql/id_type_spec.rb +1 -1
  99. data/spec/graphql/input_object_type_spec.rb +2 -15
  100. data/spec/graphql/int_type_spec.rb +2 -2
  101. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  102. data/spec/graphql/introspection/schema_type_spec.rb +0 -1
  103. data/spec/graphql/language/generation_spec.rb +186 -21
  104. data/spec/graphql/language/lexer_spec.rb +1 -21
  105. data/spec/graphql/language/nodes_spec.rb +12 -21
  106. data/spec/graphql/language/parser_spec.rb +1 -1
  107. data/spec/graphql/query/arguments_spec.rb +15 -37
  108. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  109. data/spec/graphql/query/variables_spec.rb +1 -1
  110. data/spec/graphql/query_spec.rb +5 -31
  111. data/spec/graphql/rake_task_spec.rb +1 -3
  112. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  113. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  114. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  115. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  116. data/spec/graphql/relay/mutation_spec.rb +3 -3
  117. data/spec/graphql/relay/relation_connection_spec.rb +1 -65
  118. data/spec/graphql/schema/build_from_definition_spec.rb +4 -86
  119. data/spec/graphql/schema/enum_spec.rb +60 -0
  120. data/spec/graphql/schema/field_spec.rb +14 -0
  121. data/spec/graphql/schema/input_object_spec.rb +43 -0
  122. data/spec/graphql/schema/interface_spec.rb +98 -0
  123. data/spec/graphql/schema/object_spec.rb +119 -0
  124. data/spec/graphql/schema/printer_spec.rb +15 -92
  125. data/spec/graphql/schema/scalar_spec.rb +40 -0
  126. data/spec/graphql/schema/union_spec.rb +35 -0
  127. data/spec/graphql/schema/validation_spec.rb +1 -1
  128. data/spec/graphql/schema/warden_spec.rb +11 -11
  129. data/spec/graphql/schema_spec.rb +25 -23
  130. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -10
  131. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  132. data/spec/graphql/string_type_spec.rb +3 -3
  133. data/spec/graphql/subscriptions_spec.rb +1 -1
  134. data/spec/graphql/tracing/platform_tracing_spec.rb +1 -60
  135. data/spec/support/dummy/schema.rb +25 -39
  136. data/spec/support/jazz.rb +334 -0
  137. data/spec/support/lazy_helpers.rb +21 -23
  138. data/spec/support/star_wars/data.rb +7 -6
  139. data/spec/support/star_wars/schema.rb +109 -142
  140. metadata +39 -33
  141. data/lib/graphql/execution/instrumentation.rb +0 -82
  142. data/lib/graphql/language/block_string.rb +0 -47
  143. data/lib/graphql/language/document_from_schema_definition.rb +0 -277
  144. data/lib/graphql/language/printer.rb +0 -351
  145. data/lib/graphql/tracing/data_dog_tracing.rb +0 -49
  146. data/spec/graphql/execution/instrumentation_spec.rb +0 -165
  147. data/spec/graphql/language/block_string_spec.rb +0 -70
  148. data/spec/graphql/language/document_from_schema_definition_spec.rb +0 -770
  149. data/spec/graphql/language/printer_spec.rb +0 -203
data/lib/graphql/field.rb CHANGED
@@ -102,7 +102,7 @@ module GraphQL
102
102
  # @example Calculating the complexity of a list field
103
103
  # field :items, types[ItemType] do
104
104
  # argument :limit, !types.Int
105
- # # Multiply the child complexity by the possible items on the list
105
+ # # Mulitply the child complexity by the possible items on the list
106
106
  # complexity ->(ctx, args, child_complexity) { child_complexity * args[:limit] }
107
107
  # end
108
108
  #
@@ -130,8 +130,6 @@ module GraphQL
130
130
  :relay_node_field,
131
131
  :relay_nodes_field,
132
132
  :subscription_scope,
133
- :trace,
134
- :introspection,
135
133
  argument: GraphQL::Define::AssignArgument
136
134
 
137
135
  ensure_defined(
@@ -139,8 +137,7 @@ module GraphQL
139
137
  :mutation, :arguments, :complexity, :function,
140
138
  :resolve, :resolve=, :lazy_resolve, :lazy_resolve=, :lazy_resolve_proc, :resolve_proc,
141
139
  :type, :type=, :name=, :property=, :hash_key=,
142
- :relay_node_field, :relay_nodes_field, :edges?, :edge_class, :subscription_scope,
143
- :introspection?
140
+ :relay_node_field, :relay_nodes_field, :edges?, :edge_class, :subscription_scope
144
141
  )
145
142
 
146
143
  # @return [Boolean] True if this is the Relay find-by-id field
@@ -185,16 +182,10 @@ module GraphQL
185
182
  attr_accessor :arguments_class
186
183
 
187
184
  attr_writer :connection
188
- attr_writer :introspection
189
185
 
190
186
  # @return [nil, String] Prefix for subscription names from this field
191
187
  attr_accessor :subscription_scope
192
188
 
193
- # @return [Boolean] True if this field should be traced. By default, fields are only traced if they are not a ScalarType or EnumType.
194
- attr_accessor :trace
195
-
196
- attr_accessor :ast_node
197
-
198
189
  # @return [Boolean]
199
190
  def connection?
200
191
  @connection
@@ -221,20 +212,14 @@ module GraphQL
221
212
  @connection = false
222
213
  @connection_max_page_size = nil
223
214
  @edge_class = nil
224
- @trace = nil
225
- @introspection = false
226
215
  end
227
216
 
228
217
  def initialize_copy(other)
218
+ ensure_defined
229
219
  super
230
220
  @arguments = other.arguments.dup
231
221
  end
232
222
 
233
- # @return [Boolean] Is this field a predefined introspection field?
234
- def introspection?
235
- @introspection
236
- end
237
-
238
223
  # Get a value for this field
239
224
  # @example resolving a field value
240
225
  # field.resolve(obj, args, ctx)
@@ -290,8 +275,8 @@ module GraphQL
290
275
  "<Field name:#{name || "not-named"} desc:#{description} resolve:#{resolve_proc}>"
291
276
  end
292
277
 
293
- # If {#resolve} returned an object which should be handled lazily,
294
- # this method will be called later to force the object to return its value.
278
+ # If {#resolve} returned and object which should be handled lazily,
279
+ # this method will be called later force the object to return its value.
295
280
  # @param obj [Object] The {#resolve}-provided object, registered with {Schema#lazy_resolve}
296
281
  # @param args [GraphQL::Query::Arguments] Arguments to this field
297
282
  # @param ctx [GraphQL::Query::Context] Context for this field
@@ -97,6 +97,18 @@ module GraphQL
97
97
  end
98
98
  end
99
99
 
100
+ def build_field(function)
101
+ GraphQL::Field.define(
102
+ arguments: function.arguments,
103
+ complexity: function.complexity,
104
+ type: function.type,
105
+ resolve: function,
106
+ description: function.description,
107
+ function: function,
108
+ deprecation_reason: function.deprecation_reason,
109
+ )
110
+ end
111
+
100
112
  # Class-level reader/writer which is inherited
101
113
  # @api private
102
114
  def self.inherited_value(name)
@@ -84,7 +84,6 @@ module GraphQL
84
84
 
85
85
  def coerce_non_null_input(value, ctx)
86
86
  input_values = {}
87
- defaults_used = Set.new
88
87
 
89
88
  arguments.each do |input_key, input_field_defn|
90
89
  field_value = value[input_key]
@@ -94,11 +93,10 @@ module GraphQL
94
93
  input_values[input_key] = input_field_defn.prepare(coerced_value, ctx)
95
94
  elsif input_field_defn.default_value?
96
95
  input_values[input_key] = input_field_defn.default_value
97
- defaults_used << input_key
98
96
  end
99
97
  end
100
98
 
101
- arguments_class.new(input_values, defaults_used)
99
+ arguments_class.new(input_values, context: ctx)
102
100
  end
103
101
 
104
102
  # @api private
@@ -4,12 +4,6 @@ module GraphQL
4
4
  class Node
5
5
  # @api private
6
6
  DEFAULT_TYPED_CHILDREN = Proc.new { |h, k| h[k] = {} }
7
-
8
- # A specialized, reusable object for leaf nodes.
9
- NO_TYPED_CHILDREN = Hash.new({}.freeze)
10
- def NO_TYPED_CHILDREN.dup; self; end;
11
- NO_TYPED_CHILDREN.freeze
12
-
13
7
  # @return [String] the name this node has in the response
14
8
  attr_reader :name
15
9
 
@@ -22,9 +16,9 @@ module GraphQL
22
16
  # This value is derived from {#scoped_children} after the rewrite is finished.
23
17
  # @return [Hash<GraphQL::ObjectType, Hash<String => Node>>]
24
18
  def typed_children
25
- @typed_children ||= begin
19
+ @typed_childen ||= begin
20
+ new_tc = Hash.new(&DEFAULT_TYPED_CHILDREN)
26
21
  if @scoped_children.any?
27
- new_tc = Hash.new(&DEFAULT_TYPED_CHILDREN)
28
22
  all_object_types = Set.new
29
23
  scoped_children.each_key { |t| all_object_types.merge(@query.possible_types(t)) }
30
24
  # Remove any scoped children which don't follow this return type
@@ -33,11 +27,8 @@ module GraphQL
33
27
  all_object_types.each do |t|
34
28
  new_tc[t] = get_typed_children(t)
35
29
  end
36
- new_tc
37
- else
38
- NO_TYPED_CHILDREN
39
30
  end
40
-
31
+ new_tc
41
32
  end
42
33
  end
43
34
 
@@ -134,20 +125,17 @@ module GraphQL
134
125
  @ast_nodes |= new_parent.ast_nodes
135
126
  @definitions |= new_parent.definitions
136
127
  end
137
- new_sc = new_parent.scoped_children
138
- if new_sc.any?
139
- scope ||= Scope.new(@query, @return_type.unwrap)
140
- new_sc.each do |obj_type, new_fields|
141
- inner_scope = scope.enter(obj_type)
142
- inner_scope.each do |scoped_type|
143
- prev_fields = @scoped_children[scoped_type]
144
- new_fields.each do |name, new_node|
145
- prev_node = prev_fields[name]
146
- if prev_node
147
- prev_node.deep_merge_node(new_node)
148
- else
149
- prev_fields[name] = new_node
150
- end
128
+ scope ||= Scope.new(@query, @return_type.unwrap)
129
+ new_parent.scoped_children.each do |obj_type, new_fields|
130
+ inner_scope = scope.enter(obj_type)
131
+ inner_scope.each do |scoped_type|
132
+ prev_fields = @scoped_children[scoped_type]
133
+ new_fields.each do |name, new_node|
134
+ prev_node = prev_fields[name]
135
+ if prev_node
136
+ prev_node.deep_merge_node(new_node)
137
+ else
138
+ prev_fields[name] = new_node
151
139
  end
152
140
  end
153
141
  end
@@ -24,9 +24,12 @@ module GraphQL
24
24
  # visiting the node itself and each of its typed children.
25
25
  def each_node(node)
26
26
  yield(node)
27
- node.typed_children.each do |obj_type, children|
28
- children.each do |name, node|
29
- each_node(node) { |n| yield(n) }
27
+ if node.typed_children.any?
28
+ visit_block = Proc.new
29
+ node.typed_children.each do |obj_type, children|
30
+ children.each do |name, node|
31
+ each_node(node, &visit_block)
32
+ end
30
33
  end
31
34
  end
32
35
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::ArgumentsField = GraphQL::Field.define do
3
3
  type !GraphQL::ListType.new(of_type: !GraphQL::Introspection::InputValueType)
4
- introspection true
5
4
  resolve ->(obj, args, ctx) {
6
5
  ctx.warden.arguments(obj)
7
6
  }
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::EnumValuesField = GraphQL::Field.define do
3
3
  type types[!GraphQL::Introspection::EnumValueType]
4
- introspection true
5
4
  argument :includeDeprecated, types.Boolean, default_value: false
6
5
  resolve ->(object, arguments, context) do
7
6
  if !object.kind.enum?
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::FieldsField = GraphQL::Field.define do
3
3
  type -> { types[!GraphQL::Introspection::FieldType] }
4
- introspection true
5
4
  argument :includeDeprecated, GraphQL::BOOLEAN_TYPE, default_value: false
6
5
  resolve ->(object, arguments, context) {
7
6
  return nil if !object.kind.fields?
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::InputFieldsField = GraphQL::Field.define do
3
3
  name "inputFields"
4
- introspection true
5
4
  type types[!GraphQL::Introspection::InputValueType]
6
5
  resolve ->(target, a, ctx) {
7
6
  if target.kind.input_object?
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::InterfacesField = GraphQL::Field.define do
3
3
  type -> { types[!GraphQL::Introspection::TypeType] }
4
- introspection true
5
4
  resolve ->(target, a, ctx) {
6
5
  if target.kind == GraphQL::TypeKinds::OBJECT
7
6
  ctx.warden.interfaces(target)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::OfTypeField = GraphQL::Field.define do
3
3
  name "ofType"
4
- introspection true
5
4
  type -> { GraphQL::Introspection::TypeType }
6
5
  resolve ->(obj, args, ctx) { obj.kind.wraps? ? obj.of_type : nil }
7
6
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::PossibleTypesField = GraphQL::Field.define do
3
3
  type -> { types[!GraphQL::Introspection::TypeType] }
4
- introspection true
5
4
  resolve ->(target, args, ctx) {
6
5
  if target.kind.resolves?
7
6
  ctx.warden.possible_types(target)
@@ -4,7 +4,6 @@ module GraphQL
4
4
  SchemaField = GraphQL::Field.define do
5
5
  name("__schema")
6
6
  description("This GraphQL schema")
7
- introspection true
8
7
  type(!GraphQL::Introspection::SchemaType)
9
8
  resolve ->(o, a, ctx) { ctx.query.schema }
10
9
  end
@@ -5,7 +5,6 @@ module GraphQL
5
5
  name("__type")
6
6
  description("A type in the GraphQL system")
7
7
  type(GraphQL::Introspection::TypeType)
8
- introspection true
9
8
  argument :name, !types.String
10
9
  resolve ->(o, args, ctx) {
11
10
  ctx.warden.get_type(args["name"])
@@ -5,7 +5,6 @@ module GraphQL
5
5
  name "__typename"
6
6
  description "The name of this type"
7
7
  type -> { !GraphQL::STRING_TYPE }
8
- introspection true
9
8
  resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
10
9
  end
11
10
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/language/block_string"
3
- require "graphql/language/printer"
4
2
  require "graphql/language/definition_slice"
5
- require "graphql/language/document_from_schema_definition"
6
3
  require "graphql/language/generation"
7
4
  require "graphql/language/lexer"
8
5
  require "graphql/language/nodes"
@@ -14,10 +14,189 @@ module GraphQL
14
14
  #
15
15
  # @param node [GraphQL::Language::Nodes::AbstractNode] an AST node to recursively stringify
16
16
  # @param indent [String] Whitespace to add to each printed node
17
- # @param printer [GraphQL::Language::Printer] An optional custom printer for printing AST nodes. Defaults to GraphQL::Language::Printer
18
17
  # @return [String] Valid GraphQL for `node`
19
- def generate(node, indent: "", printer: GraphQL::Language::Printer.new)
20
- printer.print(node, indent: indent)
18
+ def generate(node, indent: "")
19
+ case node
20
+ when Nodes::Document
21
+ node.definitions.map { |d| generate(d) }.join("\n\n")
22
+ when Nodes::Argument
23
+ "#{node.name}: #{generate(node.value)}".dup
24
+ when Nodes::Directive
25
+ out = "@#{node.name}".dup
26
+ out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
27
+ out
28
+ when Nodes::Enum
29
+ "#{node.name}".dup
30
+ when Nodes::NullValue
31
+ "null".dup
32
+ when Nodes::Field
33
+ out = "#{indent}".dup
34
+ out << "#{node.alias}: " if node.alias
35
+ out << "#{node.name}"
36
+ out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
37
+ out << generate_directives(node.directives)
38
+ out << generate_selections(node.selections, indent: indent)
39
+ out
40
+ when Nodes::FragmentDefinition
41
+ out = "#{indent}fragment #{node.name}".dup
42
+ if node.type
43
+ out << " on #{generate(node.type)}"
44
+ end
45
+ out << generate_directives(node.directives)
46
+ out << generate_selections(node.selections, indent: indent)
47
+ out
48
+ when Nodes::FragmentSpread
49
+ out = "#{indent}...#{node.name}".dup
50
+ out << generate_directives(node.directives)
51
+ out
52
+ when Nodes::InlineFragment
53
+ out = "#{indent}...".dup
54
+ if node.type
55
+ out << " on #{generate(node.type)}"
56
+ end
57
+ out << generate_directives(node.directives)
58
+ out << generate_selections(node.selections, indent: indent)
59
+ out
60
+ when Nodes::InputObject
61
+ generate(node.to_h)
62
+ when Nodes::ListType
63
+ "[#{generate(node.of_type)}]".dup
64
+ when Nodes::NonNullType
65
+ "#{generate(node.of_type)}!".dup
66
+ when Nodes::OperationDefinition
67
+ out = "#{indent}#{node.operation_type}".dup
68
+ out << " #{node.name}" if node.name
69
+ out << "(#{node.variables.map { |v| generate(v) }.join(", ")})" if node.variables.any?
70
+ out << generate_directives(node.directives)
71
+ out << generate_selections(node.selections, indent: indent)
72
+ out
73
+ when Nodes::TypeName
74
+ "#{node.name}".dup
75
+ when Nodes::VariableDefinition
76
+ out = "$#{node.name}: #{generate(node.type)}".dup
77
+ out << " = #{generate(node.default_value)}" unless node.default_value.nil?
78
+ out
79
+ when Nodes::VariableIdentifier
80
+ "$#{node.name}".dup
81
+ when Nodes::SchemaDefinition
82
+ if (node.query.nil? || node.query == 'Query') &&
83
+ (node.mutation.nil? || node.mutation == 'Mutation') &&
84
+ (node.subscription.nil? || node.subscription == 'Subscription')
85
+ return
86
+ end
87
+
88
+ out = "schema {\n".dup
89
+ out << " query: #{node.query}\n" if node.query
90
+ out << " mutation: #{node.mutation}\n" if node.mutation
91
+ out << " subscription: #{node.subscription}\n" if node.subscription
92
+ out << "}"
93
+ when Nodes::ScalarTypeDefinition
94
+ out = generate_description(node)
95
+ out << "scalar #{node.name}"
96
+ out << generate_directives(node.directives)
97
+ when Nodes::ObjectTypeDefinition
98
+ out = generate_description(node)
99
+ out << "type #{node.name}"
100
+ out << generate_directives(node.directives)
101
+ out << " implements " << node.interfaces.map(&:name).join(", ") unless node.interfaces.empty?
102
+ out << generate_field_definitions(node.fields)
103
+ when Nodes::InputValueDefinition
104
+ out = "#{node.name}: #{generate(node.type)}".dup
105
+ out << " = #{generate(node.default_value)}" unless node.default_value.nil?
106
+ out << generate_directives(node.directives)
107
+ when Nodes::FieldDefinition
108
+ out = node.name.dup
109
+ unless node.arguments.empty?
110
+ out << "(" << node.arguments.map{ |arg| generate(arg) }.join(", ") << ")"
111
+ end
112
+ out << ": #{generate(node.type)}"
113
+ out << generate_directives(node.directives)
114
+ when Nodes::InterfaceTypeDefinition
115
+ out = generate_description(node)
116
+ out << "interface #{node.name}"
117
+ out << generate_directives(node.directives)
118
+ out << generate_field_definitions(node.fields)
119
+ when Nodes::UnionTypeDefinition
120
+ out = generate_description(node)
121
+ out << "union #{node.name}"
122
+ out << generate_directives(node.directives)
123
+ out << " = " + node.types.map(&:name).join(" | ")
124
+ when Nodes::EnumTypeDefinition
125
+ out = generate_description(node)
126
+ out << "enum #{node.name}#{generate_directives(node.directives)} {\n"
127
+ node.values.each.with_index do |value, i|
128
+ out << generate_description(value, indent: ' ', first_in_block: i == 0)
129
+ out << generate(value)
130
+ end
131
+ out << "}"
132
+ when Nodes::EnumValueDefinition
133
+ out = " #{node.name}".dup
134
+ out << generate_directives(node.directives)
135
+ out << "\n"
136
+ when Nodes::InputObjectTypeDefinition
137
+ out = generate_description(node)
138
+ out << "input #{node.name}"
139
+ out << generate_directives(node.directives)
140
+ out << " {\n"
141
+ node.fields.each.with_index do |field, i|
142
+ out << generate_description(field, indent: ' ', first_in_block: i == 0)
143
+ out << " #{generate(field)}\n"
144
+ end
145
+ out << "}"
146
+ when Nodes::DirectiveDefinition
147
+ out = generate_description(node)
148
+ out << "directive @#{node.name}"
149
+ out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
150
+ out << " on #{node.locations.join(' | ')}"
151
+ when Nodes::AbstractNode
152
+ node.to_query_string(indent: indent)
153
+ when FalseClass, Float, Integer, NilClass, String, TrueClass
154
+ GraphQL::Language.serialize(node)
155
+ when Array
156
+ "[#{node.map { |v| generate(v) }.join(", ")}]".dup
157
+ when Hash
158
+ "{#{node.map { |k, v| "#{k}: #{generate(v)}" }.join(", ")}}".dup
159
+ else
160
+ raise TypeError
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ def generate_directives(directives)
167
+ if directives.any?
168
+ directives.map { |d| " #{generate(d)}" }.join
169
+ else
170
+ ""
171
+ end
172
+ end
173
+
174
+ def generate_selections(selections, indent: "")
175
+ if selections.any?
176
+ out = " {\n".dup
177
+ selections.each do |selection|
178
+ out << generate(selection, indent: indent + " ") << "\n"
179
+ end
180
+ out << "#{indent}}"
181
+ else
182
+ ""
183
+ end
184
+ end
185
+
186
+ def generate_description(node, indent: '', first_in_block: true)
187
+ return ''.dup unless node.description
188
+
189
+ description = indent != '' && !first_in_block ? "\n".dup : "".dup
190
+ description << GraphQL::Language::Comments.commentize(node.description, indent: indent)
191
+ end
192
+
193
+ def generate_field_definitions(fields)
194
+ out = " {\n".dup
195
+ fields.each.with_index do |field, i|
196
+ out << generate_description(field, indent: ' ', first_in_block: i == 0)
197
+ out << " #{generate(field)}\n"
198
+ end
199
+ out << "}"
21
200
  end
22
201
  end
23
202
  end