graphql 1.7.14 → 1.8.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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