graphql 2.0.13 → 2.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/relay.rb +18 -1
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_object.erb +2 -0
  17. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +8 -0
  26. data/lib/graphql/analysis/analyzer.rb +89 -0
  27. data/lib/graphql/analysis/field_usage.rb +82 -0
  28. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  29. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  30. data/lib/graphql/analysis/query_complexity.rb +183 -0
  31. data/lib/graphql/analysis/query_depth.rb +58 -0
  32. data/lib/graphql/analysis/visitor.rb +283 -0
  33. data/lib/graphql/analysis.rb +92 -1
  34. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  35. data/lib/graphql/backtrace/table.rb +2 -2
  36. data/lib/graphql/backtrace/trace.rb +93 -0
  37. data/lib/graphql/backtrace/tracer.rb +1 -1
  38. data/lib/graphql/backtrace.rb +2 -1
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/request.rb +5 -0
  43. data/lib/graphql/dataloader/source.rb +89 -45
  44. data/lib/graphql/dataloader.rb +115 -142
  45. data/lib/graphql/duration_encoding_error.rb +16 -0
  46. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  47. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  48. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
  49. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  50. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +331 -455
  52. data/lib/graphql/execution/interpreter.rb +125 -61
  53. data/lib/graphql/execution/lazy.rb +6 -12
  54. data/lib/graphql/execution/lookahead.rb +124 -46
  55. data/lib/graphql/execution/multiplex.rb +3 -117
  56. data/lib/graphql/execution.rb +0 -1
  57. data/lib/graphql/introspection/directive_type.rb +3 -3
  58. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  59. data/lib/graphql/introspection/entry_points.rb +11 -5
  60. data/lib/graphql/introspection/field_type.rb +2 -2
  61. data/lib/graphql/introspection/schema_type.rb +10 -13
  62. data/lib/graphql/introspection/type_type.rb +17 -10
  63. data/lib/graphql/introspection.rb +3 -2
  64. data/lib/graphql/language/block_string.rb +34 -18
  65. data/lib/graphql/language/definition_slice.rb +1 -1
  66. data/lib/graphql/language/document_from_schema_definition.rb +75 -59
  67. data/lib/graphql/language/lexer.rb +358 -1506
  68. data/lib/graphql/language/nodes.rb +166 -93
  69. data/lib/graphql/language/parser.rb +795 -1953
  70. data/lib/graphql/language/printer.rb +340 -160
  71. data/lib/graphql/language/sanitized_printer.rb +21 -23
  72. data/lib/graphql/language/static_visitor.rb +167 -0
  73. data/lib/graphql/language/visitor.rb +188 -141
  74. data/lib/graphql/language.rb +61 -1
  75. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  76. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  77. data/lib/graphql/pagination/array_connection.rb +6 -6
  78. data/lib/graphql/pagination/connection.rb +33 -6
  79. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  80. data/lib/graphql/query/context/scoped_context.rb +101 -0
  81. data/lib/graphql/query/context.rb +117 -112
  82. data/lib/graphql/query/null_context.rb +12 -25
  83. data/lib/graphql/query/validation_pipeline.rb +6 -5
  84. data/lib/graphql/query/variables.rb +3 -3
  85. data/lib/graphql/query.rb +86 -30
  86. data/lib/graphql/railtie.rb +9 -6
  87. data/lib/graphql/rake_task.rb +29 -11
  88. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  89. data/lib/graphql/schema/addition.rb +59 -23
  90. data/lib/graphql/schema/always_visible.rb +11 -0
  91. data/lib/graphql/schema/argument.rb +55 -26
  92. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  93. data/lib/graphql/schema/build_from_definition.rb +56 -32
  94. data/lib/graphql/schema/directive/one_of.rb +24 -0
  95. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  96. data/lib/graphql/schema/directive/transform.rb +1 -1
  97. data/lib/graphql/schema/directive.rb +15 -3
  98. data/lib/graphql/schema/enum.rb +35 -24
  99. data/lib/graphql/schema/enum_value.rb +2 -3
  100. data/lib/graphql/schema/field/connection_extension.rb +2 -16
  101. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  102. data/lib/graphql/schema/field.rb +147 -107
  103. data/lib/graphql/schema/field_extension.rb +1 -4
  104. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  105. data/lib/graphql/schema/has_single_input_argument.rb +158 -0
  106. data/lib/graphql/schema/input_object.rb +47 -11
  107. data/lib/graphql/schema/interface.rb +15 -21
  108. data/lib/graphql/schema/introspection_system.rb +7 -17
  109. data/lib/graphql/schema/late_bound_type.rb +10 -0
  110. data/lib/graphql/schema/list.rb +2 -2
  111. data/lib/graphql/schema/loader.rb +2 -3
  112. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
  113. data/lib/graphql/schema/member/build_type.rb +11 -3
  114. data/lib/graphql/schema/member/has_arguments.rb +170 -130
  115. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  116. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  117. data/lib/graphql/schema/member/has_directives.rb +81 -61
  118. data/lib/graphql/schema/member/has_fields.rb +100 -38
  119. data/lib/graphql/schema/member/has_interfaces.rb +65 -10
  120. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  121. data/lib/graphql/schema/member/has_validators.rb +32 -6
  122. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  123. data/lib/graphql/schema/member/scoped.rb +19 -0
  124. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  125. data/lib/graphql/schema/member/validates_input.rb +3 -3
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +16 -5
  128. data/lib/graphql/schema/printer.rb +11 -8
  129. data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
  130. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  131. data/lib/graphql/schema/resolver.rb +47 -32
  132. data/lib/graphql/schema/scalar.rb +3 -3
  133. data/lib/graphql/schema/subscription.rb +11 -4
  134. data/lib/graphql/schema/subset.rb +397 -0
  135. data/lib/graphql/schema/timeout.rb +25 -29
  136. data/lib/graphql/schema/type_expression.rb +2 -2
  137. data/lib/graphql/schema/type_membership.rb +3 -0
  138. data/lib/graphql/schema/union.rb +11 -2
  139. data/lib/graphql/schema/unique_within_type.rb +1 -1
  140. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  141. data/lib/graphql/schema/validator.rb +4 -2
  142. data/lib/graphql/schema/warden.rb +238 -93
  143. data/lib/graphql/schema.rb +498 -103
  144. data/lib/graphql/static_validation/all_rules.rb +2 -1
  145. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  146. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  147. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  148. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  149. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  150. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  151. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  152. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  153. data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
  154. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  155. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  156. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  158. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  159. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  160. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  161. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  163. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  164. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  165. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  166. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  167. data/lib/graphql/static_validation/validation_context.rb +5 -5
  168. data/lib/graphql/static_validation/validator.rb +4 -1
  169. data/lib/graphql/static_validation.rb +0 -1
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
  171. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  172. data/lib/graphql/subscriptions/event.rb +11 -10
  173. data/lib/graphql/subscriptions/serialize.rb +2 -0
  174. data/lib/graphql/subscriptions.rb +20 -13
  175. data/lib/graphql/testing/helpers.rb +151 -0
  176. data/lib/graphql/testing.rb +2 -0
  177. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  178. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  179. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  180. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  181. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  182. data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
  183. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  184. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  185. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  186. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  187. data/lib/graphql/tracing/platform_trace.rb +118 -0
  188. data/lib/graphql/tracing/platform_tracing.rb +17 -3
  189. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  190. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  191. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  192. data/lib/graphql/tracing/scout_trace.rb +72 -0
  193. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  194. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  195. data/lib/graphql/tracing/trace.rb +76 -0
  196. data/lib/graphql/tracing.rb +20 -40
  197. data/lib/graphql/type_kinds.rb +7 -4
  198. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  199. data/lib/graphql/types/relay/base_connection.rb +1 -1
  200. data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
  201. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  202. data/lib/graphql/types/relay/node_behaviors.rb +8 -2
  203. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  204. data/lib/graphql/types/relay.rb +0 -1
  205. data/lib/graphql/types/string.rb +1 -1
  206. data/lib/graphql/types.rb +1 -0
  207. data/lib/graphql/version.rb +1 -1
  208. data/lib/graphql.rb +27 -20
  209. data/readme.md +13 -3
  210. metadata +96 -47
  211. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  212. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  213. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  214. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  215. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  216. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  217. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  218. data/lib/graphql/analysis/ast.rb +0 -81
  219. data/lib/graphql/deprecation.rb +0 -9
  220. data/lib/graphql/filter.rb +0 -53
  221. data/lib/graphql/language/lexer.rl +0 -280
  222. data/lib/graphql/language/parser.y +0 -554
  223. data/lib/graphql/language/token.rb +0 -34
  224. data/lib/graphql/schema/base_64_bp.rb +0 -26
  225. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  226. data/lib/graphql/static_validation/type_stack.rb +0 -216
  227. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
  228. data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -2,6 +2,32 @@
2
2
  module GraphQL
3
3
  module Language
4
4
  class Printer
5
+ OMISSION = "... (truncated)"
6
+
7
+ class TruncatableBuffer
8
+ class TruncateSizeReached < StandardError; end
9
+
10
+ DEFAULT_INIT_CAPACITY = 500
11
+
12
+ def initialize(truncate_size: nil)
13
+ @out = String.new(capacity: truncate_size || DEFAULT_INIT_CAPACITY)
14
+ @truncate_size = truncate_size
15
+ end
16
+
17
+ def append(other)
18
+ if @truncate_size && (@out.size + other.size) > @truncate_size
19
+ @out << other.slice(0, @truncate_size - @out.size)
20
+ raise(TruncateSizeReached, "Truncate size reached")
21
+ else
22
+ @out << other
23
+ end
24
+ end
25
+
26
+ def to_string
27
+ @out
28
+ end
29
+ end
30
+
5
31
  # Turn an arbitrary AST node back into a string.
6
32
  #
7
33
  # @example Turning a document into a query string
@@ -14,292 +40,424 @@ module GraphQL
14
40
  #
15
41
  # class MyPrinter < GraphQL::Language::Printer
16
42
  # def print_argument(arg)
17
- # "#{arg.name}: <HIDDEN>"
43
+ # print_string("#{arg.name}: <HIDDEN>")
18
44
  # end
19
45
  # end
20
46
  #
21
47
  # MyPrinter.new.print(document)
22
48
  # # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
23
49
  #
24
- #
50
+ # @param node [Nodes::AbstractNode]
25
51
  # @param indent [String] Whitespace to add to the printed node
52
+ # @param truncate_size [Integer, nil] The size to truncate to.
26
53
  # @return [String] Valid GraphQL for `node`
27
- def print(node, indent: "")
54
+ def print(node, indent: "", truncate_size: nil)
55
+ truncate_size = truncate_size ? [truncate_size - OMISSION.size, 0].max : nil
56
+ @out = TruncatableBuffer.new(truncate_size: truncate_size)
28
57
  print_node(node, indent: indent)
58
+ @out.to_string
59
+ rescue TruncatableBuffer::TruncateSizeReached
60
+ @out.to_string << OMISSION
29
61
  end
30
62
 
31
63
  protected
32
64
 
65
+ def print_string(str)
66
+ @out.append(str)
67
+ end
68
+
33
69
  def print_document(document)
34
- document.definitions.map { |d| print_node(d) }.join("\n\n")
70
+ document.definitions.each_with_index do |d, i|
71
+ print_node(d)
72
+ print_string("\n\n") if i < document.definitions.size - 1
73
+ end
35
74
  end
36
75
 
37
76
  def print_argument(argument)
38
- "#{argument.name}: #{print_node(argument.value)}".dup
77
+ print_string(argument.name)
78
+ print_string(": ")
79
+ print_node(argument.value)
80
+ end
81
+
82
+ def print_input_object(input_object)
83
+ print_string("{")
84
+ input_object.arguments.each_with_index do |a, i|
85
+ print_argument(a)
86
+ print_string(", ") if i < input_object.arguments.size - 1
87
+ end
88
+ print_string("}")
39
89
  end
40
90
 
41
91
  def print_directive(directive)
42
- out = "@#{directive.name}".dup
92
+ print_string("@")
93
+ print_string(directive.name)
43
94
 
44
95
  if directive.arguments.any?
45
- out << "(#{directive.arguments.map { |a| print_argument(a) }.join(", ")})"
96
+ print_string("(")
97
+ directive.arguments.each_with_index do |a, i|
98
+ print_argument(a)
99
+ print_string(", ") if i < directive.arguments.size - 1
100
+ end
101
+ print_string(")")
46
102
  end
47
-
48
- out
49
103
  end
50
104
 
51
105
  def print_enum(enum)
52
- "#{enum.name}".dup
106
+ print_string(enum.name)
53
107
  end
54
108
 
55
109
  def print_null_value
56
- "null".dup
110
+ print_string("null")
57
111
  end
58
112
 
59
113
  def print_field(field, indent: "")
60
- out = "#{indent}".dup
61
- out << "#{field.alias}: " if field.alias
62
- out << "#{field.name}"
63
- out << "(#{field.arguments.map { |a| print_argument(a) }.join(", ")})" if field.arguments.any?
64
- out << print_directives(field.directives)
65
- out << print_selections(field.selections, indent: indent)
66
- out
114
+ print_string(indent)
115
+ if field.alias
116
+ print_string(field.alias)
117
+ print_string(": ")
118
+ end
119
+ print_string(field.name)
120
+ if field.arguments.any?
121
+ print_string("(")
122
+ field.arguments.each_with_index do |a, i|
123
+ print_argument(a)
124
+ print_string(", ") if i < field.arguments.size - 1
125
+ end
126
+ print_string(")")
127
+ end
128
+ print_directives(field.directives)
129
+ print_selections(field.selections, indent: indent)
67
130
  end
68
131
 
69
132
  def print_fragment_definition(fragment_def, indent: "")
70
- out = "#{indent}fragment #{fragment_def.name}".dup
133
+ print_string(indent)
134
+ print_string("fragment")
135
+ if fragment_def.name
136
+ print_string(" ")
137
+ print_string(fragment_def.name)
138
+ end
139
+
71
140
  if fragment_def.type
72
- out << " on #{print_node(fragment_def.type)}"
141
+ print_string(" on ")
142
+ print_node(fragment_def.type)
73
143
  end
74
- out << print_directives(fragment_def.directives)
75
- out << print_selections(fragment_def.selections, indent: indent)
76
- out
144
+ print_directives(fragment_def.directives)
145
+ print_selections(fragment_def.selections, indent: indent)
77
146
  end
78
147
 
79
148
  def print_fragment_spread(fragment_spread, indent: "")
80
- out = "#{indent}...#{fragment_spread.name}".dup
81
- out << print_directives(fragment_spread.directives)
82
- out
149
+ print_string(indent)
150
+ print_string("...")
151
+ print_string(fragment_spread.name)
152
+ print_directives(fragment_spread.directives)
83
153
  end
84
154
 
85
155
  def print_inline_fragment(inline_fragment, indent: "")
86
- out = "#{indent}...".dup
156
+ print_string(indent)
157
+ print_string("...")
87
158
  if inline_fragment.type
88
- out << " on #{print_node(inline_fragment.type)}"
159
+ print_string(" on ")
160
+ print_node(inline_fragment.type)
89
161
  end
90
- out << print_directives(inline_fragment.directives)
91
- out << print_selections(inline_fragment.selections, indent: indent)
92
- out
93
- end
94
-
95
- def print_input_object(input_object)
96
- "{#{input_object.arguments.map { |a| print_argument(a) }.join(", ")}}"
162
+ print_directives(inline_fragment.directives)
163
+ print_selections(inline_fragment.selections, indent: indent)
97
164
  end
98
165
 
99
166
  def print_list_type(list_type)
100
- "[#{print_node(list_type.of_type)}]".dup
167
+ print_string("[")
168
+ print_node(list_type.of_type)
169
+ print_string("]")
101
170
  end
102
171
 
103
172
  def print_non_null_type(non_null_type)
104
- "#{print_node(non_null_type.of_type)}!".dup
173
+ print_node(non_null_type.of_type)
174
+ print_string("!")
105
175
  end
106
176
 
107
177
  def print_operation_definition(operation_definition, indent: "")
108
- out = "#{indent}#{operation_definition.operation_type}".dup
109
- out << " #{operation_definition.name}" if operation_definition.name
178
+ print_string(indent)
179
+ print_string(operation_definition.operation_type)
180
+ if operation_definition.name
181
+ print_string(" ")
182
+ print_string(operation_definition.name)
183
+ end
110
184
 
111
185
  if operation_definition.variables.any?
112
- out << "(#{operation_definition.variables.map { |v| print_variable_definition(v) }.join(", ")})"
186
+ print_string("(")
187
+ operation_definition.variables.each_with_index do |v, i|
188
+ print_variable_definition(v)
189
+ print_string(", ") if i < operation_definition.variables.size - 1
190
+ end
191
+ print_string(")")
113
192
  end
114
193
 
115
- out << print_directives(operation_definition.directives)
116
- out << print_selections(operation_definition.selections, indent: indent)
117
- out
194
+ print_directives(operation_definition.directives)
195
+ print_selections(operation_definition.selections, indent: indent)
118
196
  end
119
197
 
120
198
  def print_type_name(type_name)
121
- "#{type_name.name}".dup
199
+ print_string(type_name.name)
122
200
  end
123
201
 
124
202
  def print_variable_definition(variable_definition)
125
- out = "$#{variable_definition.name}: #{print_node(variable_definition.type)}".dup
126
- out << " = #{print_node(variable_definition.default_value)}" unless variable_definition.default_value.nil?
127
- out
203
+ print_string("$")
204
+ print_string(variable_definition.name)
205
+ print_string(": ")
206
+ print_node(variable_definition.type)
207
+ unless variable_definition.default_value.nil?
208
+ print_string(" = ")
209
+ print_node(variable_definition.default_value)
210
+ end
211
+ variable_definition.directives.each do |dir|
212
+ print_string(" ")
213
+ print_directive(dir)
214
+ end
128
215
  end
129
216
 
130
217
  def print_variable_identifier(variable_identifier)
131
- "$#{variable_identifier.name}".dup
218
+ print_string("$")
219
+ print_string(variable_identifier.name)
132
220
  end
133
221
 
134
- def print_schema_definition(schema)
135
- if (schema.query.nil? || schema.query == 'Query') &&
136
- (schema.mutation.nil? || schema.mutation == 'Mutation') &&
137
- (schema.subscription.nil? || schema.subscription == 'Subscription') &&
138
- (schema.directives.empty?)
222
+ def print_schema_definition(schema, extension: false)
223
+ has_conventional_names = (schema.query.nil? || schema.query == 'Query') &&
224
+ (schema.mutation.nil? || schema.mutation == 'Mutation') &&
225
+ (schema.subscription.nil? || schema.subscription == 'Subscription')
226
+
227
+ if has_conventional_names && schema.directives.empty?
139
228
  return
140
229
  end
141
230
 
142
- out = "schema".dup
231
+ extension ? print_string("extend schema") : print_string("schema")
232
+
143
233
  if schema.directives.any?
144
234
  schema.directives.each do |dir|
145
- out << "\n "
146
- out << print_node(dir)
235
+ print_string("\n ")
236
+ print_node(dir)
237
+ end
238
+
239
+ if !has_conventional_names
240
+ print_string("\n")
147
241
  end
148
- out << "\n{"
149
- else
150
- out << " {\n"
151
242
  end
152
- out << " query: #{schema.query}\n" if schema.query
153
- out << " mutation: #{schema.mutation}\n" if schema.mutation
154
- out << " subscription: #{schema.subscription}\n" if schema.subscription
155
- out << "}"
243
+
244
+ if !has_conventional_names
245
+ if schema.directives.empty?
246
+ print_string(" ")
247
+ end
248
+ print_string("{\n")
249
+ print_string(" query: #{schema.query}\n") if schema.query
250
+ print_string(" mutation: #{schema.mutation}\n") if schema.mutation
251
+ print_string(" subscription: #{schema.subscription}\n") if schema.subscription
252
+ print_string("}")
253
+ end
156
254
  end
157
255
 
158
- def print_scalar_type_definition(scalar_type)
159
- out = print_description(scalar_type)
160
- out << "scalar #{scalar_type.name}"
161
- out << print_directives(scalar_type.directives)
256
+
257
+ def print_scalar_type_definition(scalar_type, extension: false)
258
+ extension ? print_string("extend ") : print_description(scalar_type)
259
+ print_string("scalar ")
260
+ print_string(scalar_type.name)
261
+ print_directives(scalar_type.directives)
162
262
  end
163
263
 
164
- def print_object_type_definition(object_type)
165
- out = print_description(object_type)
166
- out << "type #{object_type.name}"
167
- out << print_implements(object_type) unless object_type.interfaces.empty?
168
- out << print_directives(object_type.directives)
169
- out << print_field_definitions(object_type.fields)
264
+ def print_object_type_definition(object_type, extension: false)
265
+ extension ? print_string("extend ") : print_description(object_type)
266
+ print_string("type ")
267
+ print_string(object_type.name)
268
+ print_implements(object_type) unless object_type.interfaces.empty?
269
+ print_directives(object_type.directives)
270
+ print_field_definitions(object_type.fields)
170
271
  end
171
272
 
172
273
  def print_implements(type)
173
- " implements #{type.interfaces.map(&:name).join(" & ")}"
274
+ print_string(" implements ")
275
+ i = 0
276
+ type.interfaces.each do |int|
277
+ if i > 0
278
+ print_string(" & ")
279
+ end
280
+ print_string(int.name)
281
+ i += 1
282
+ end
174
283
  end
175
284
 
176
285
  def print_input_value_definition(input_value)
177
- out = "#{input_value.name}: #{print_node(input_value.type)}".dup
178
- out << " = #{print_node(input_value.default_value)}" unless input_value.default_value.nil?
179
- out << print_directives(input_value.directives)
286
+ print_string(input_value.name)
287
+ print_string(": ")
288
+ print_node(input_value.type)
289
+ unless input_value.default_value.nil?
290
+ print_string(" = ")
291
+ print_node(input_value.default_value)
292
+ end
293
+ print_directives(input_value.directives)
180
294
  end
181
295
 
182
296
  def print_arguments(arguments, indent: "")
183
- if arguments.all?{ |arg| !arg.description }
184
- return "(#{arguments.map{ |arg| print_input_value_definition(arg) }.join(", ")})"
297
+ if arguments.all? { |arg| !arg.description }
298
+ print_string("(")
299
+ arguments.each_with_index do |arg, i|
300
+ print_input_value_definition(arg)
301
+ print_string(", ") if i < arguments.size - 1
302
+ end
303
+ print_string(")")
304
+ return
185
305
  end
186
306
 
187
- out = "(\n".dup
188
- out << arguments.map.with_index{ |arg, i|
189
- "#{print_description(arg, indent: " " + indent, first_in_block: i == 0)} #{indent}"\
190
- "#{print_input_value_definition(arg)}"
191
- }.join("\n")
192
- out << "\n#{indent})"
307
+ print_string("(\n")
308
+ arguments.each_with_index do |arg, i|
309
+ print_description(arg, indent: " " + indent, first_in_block: i == 0)
310
+ print_string(" ")
311
+ print_string(indent)
312
+ print_input_value_definition(arg)
313
+ print_string("\n") if i < arguments.size - 1
314
+ end
315
+ print_string("\n")
316
+ print_string(indent)
317
+ print_string(")")
193
318
  end
194
319
 
195
320
  def print_field_definition(field)
196
- out = field.name.dup
321
+ print_string(field.name)
197
322
  unless field.arguments.empty?
198
- out << print_arguments(field.arguments, indent: " ")
323
+ print_arguments(field.arguments, indent: " ")
324
+ end
325
+ print_string(": ")
326
+ print_node(field.type)
327
+ print_directives(field.directives)
328
+ end
329
+
330
+ def print_interface_type_definition(interface_type, extension: false)
331
+ extension ? print_string("extend ") : print_description(interface_type)
332
+ print_string("interface ")
333
+ print_string(interface_type.name)
334
+ print_implements(interface_type) if interface_type.interfaces.any?
335
+ print_directives(interface_type.directives)
336
+ print_field_definitions(interface_type.fields)
337
+ end
338
+
339
+ def print_union_type_definition(union_type, extension: false)
340
+ extension ? print_string("extend ") : print_description(union_type)
341
+ print_string("union ")
342
+ print_string(union_type.name)
343
+ print_directives(union_type.directives)
344
+ if union_type.types.any?
345
+ print_string(" = ")
346
+ i = 0
347
+ union_type.types.each do |t|
348
+ if i > 0
349
+ print_string(" | ")
350
+ end
351
+ print_string(t.name)
352
+ i += 1
353
+ end
199
354
  end
200
- out << ": #{print_node(field.type)}"
201
- out << print_directives(field.directives)
202
- end
203
-
204
- def print_interface_type_definition(interface_type)
205
- out = print_description(interface_type)
206
- out << "interface #{interface_type.name}"
207
- out << print_implements(interface_type) if interface_type.interfaces.any?
208
- out << print_directives(interface_type.directives)
209
- out << print_field_definitions(interface_type.fields)
210
- end
211
-
212
- def print_union_type_definition(union_type)
213
- out = print_description(union_type)
214
- out << "union #{union_type.name}"
215
- out << print_directives(union_type.directives)
216
- out << " = " + union_type.types.map(&:name).join(" | ")
217
355
  end
218
356
 
219
- def print_enum_type_definition(enum_type)
220
- out = print_description(enum_type)
221
- out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
222
- enum_type.values.each.with_index do |value, i|
223
- out << print_description(value, indent: ' ', first_in_block: i == 0)
224
- out << print_enum_value_definition(value)
357
+ def print_enum_type_definition(enum_type, extension: false)
358
+ extension ? print_string("extend ") : print_description(enum_type)
359
+ print_string("enum ")
360
+ print_string(enum_type.name)
361
+ print_directives(enum_type.directives)
362
+ if enum_type.values.any?
363
+ print_string(" {\n")
364
+ enum_type.values.each.with_index do |value, i|
365
+ print_description(value, indent: " ", first_in_block: i == 0)
366
+ print_enum_value_definition(value)
367
+ end
368
+ print_string("}")
225
369
  end
226
- out << "}"
227
370
  end
228
371
 
229
372
  def print_enum_value_definition(enum_value)
230
- out = " #{enum_value.name}".dup
231
- out << print_directives(enum_value.directives)
232
- out << "\n"
373
+ print_string(" ")
374
+ print_string(enum_value.name)
375
+ print_directives(enum_value.directives)
376
+ print_string("\n")
233
377
  end
234
378
 
235
- def print_input_object_type_definition(input_object_type)
236
- out = print_description(input_object_type)
237
- out << "input #{input_object_type.name}"
238
- out << print_directives(input_object_type.directives)
379
+ def print_input_object_type_definition(input_object_type, extension: false)
380
+ extension ? print_string("extend ") : print_description(input_object_type)
381
+ print_string("input ")
382
+ print_string(input_object_type.name)
383
+ print_directives(input_object_type.directives)
239
384
  if !input_object_type.fields.empty?
240
- out << " {\n"
385
+ print_string(" {\n")
241
386
  input_object_type.fields.each.with_index do |field, i|
242
- out << print_description(field, indent: ' ', first_in_block: i == 0)
243
- out << " #{print_input_value_definition(field)}\n"
387
+ print_description(field, indent: " ", first_in_block: i == 0)
388
+ print_string(" ")
389
+ print_input_value_definition(field)
390
+ print_string("\n")
244
391
  end
245
- out << "}"
392
+ print_string("}")
246
393
  end
247
- out
248
394
  end
249
395
 
250
396
  def print_directive_definition(directive)
251
- out = print_description(directive)
252
- out << "directive @#{directive.name}"
397
+ print_description(directive)
398
+ print_string("directive @")
399
+ print_string(directive.name)
253
400
 
254
401
  if directive.arguments.any?
255
- out << print_arguments(directive.arguments)
402
+ print_arguments(directive.arguments)
256
403
  end
257
404
 
258
405
  if directive.repeatable
259
- out << " repeatable"
406
+ print_string(" repeatable")
260
407
  end
261
408
 
262
- out << " on #{directive.locations.map(&:name).join(' | ')}"
409
+ print_string(" on ")
410
+ i = 0
411
+ directive.locations.each do |loc|
412
+ if i > 0
413
+ print_string(" | ")
414
+ end
415
+ print_string(loc.name)
416
+ i += 1
417
+ end
263
418
  end
264
419
 
265
420
  def print_description(node, indent: "", first_in_block: true)
266
- return ''.dup unless node.description
421
+ return unless node.description
267
422
 
268
- description = indent != '' && !first_in_block ? "\n".dup : "".dup
269
- description << GraphQL::Language::BlockString.print(node.description, indent: indent)
423
+ print_string("\n") if indent != "" && !first_in_block
424
+ print_string(GraphQL::Language::BlockString.print(node.description, indent: indent))
270
425
  end
271
426
 
272
427
  def print_field_definitions(fields)
273
- if fields.empty?
274
- ""
275
- else
276
- out = " {\n".dup
277
- fields.each.with_index do |field, i|
278
- out << print_description(field, indent: ' ', first_in_block: i == 0)
279
- out << " #{print_field_definition(field)}\n"
280
- end
281
- out << "}"
428
+ return if fields.empty?
429
+
430
+ print_string(" {\n")
431
+ i = 0
432
+ fields.each do |field|
433
+ print_description(field, indent: " ", first_in_block: i == 0)
434
+ print_string(" ")
435
+ print_field_definition(field)
436
+ print_string("\n")
437
+ i += 1
282
438
  end
439
+ print_string("}")
283
440
  end
284
441
 
285
442
  def print_directives(directives)
286
- if directives.any?
287
- directives.map { |d| " #{print_directive(d)}" }.join
288
- else
289
- ""
443
+ return if directives.empty?
444
+
445
+ directives.each do |d|
446
+ print_string(" ")
447
+ print_directive(d)
290
448
  end
291
449
  end
292
450
 
293
451
  def print_selections(selections, indent: "")
294
- if selections.any?
295
- out = " {\n".dup
296
- selections.each do |selection|
297
- out << print_node(selection, indent: indent + " ") << "\n"
298
- end
299
- out << "#{indent}}"
300
- else
301
- ""
452
+ return if selections.empty?
453
+
454
+ print_string(" {\n")
455
+ selections.each do |selection|
456
+ print_node(selection, indent: indent + " ")
457
+ print_string("\n")
302
458
  end
459
+ print_string(indent)
460
+ print_string("}")
303
461
  end
304
462
 
305
463
  def print_node(node, indent: "")
@@ -338,40 +496,62 @@ module GraphQL
338
496
  print_variable_identifier(node)
339
497
  when Nodes::SchemaDefinition
340
498
  print_schema_definition(node)
499
+ when Nodes::SchemaExtension
500
+ print_schema_definition(node, extension: true)
341
501
  when Nodes::ScalarTypeDefinition
342
502
  print_scalar_type_definition(node)
503
+ when Nodes::ScalarTypeExtension
504
+ print_scalar_type_definition(node, extension: true)
343
505
  when Nodes::ObjectTypeDefinition
344
506
  print_object_type_definition(node)
507
+ when Nodes::ObjectTypeExtension
508
+ print_object_type_definition(node, extension: true)
345
509
  when Nodes::InputValueDefinition
346
510
  print_input_value_definition(node)
347
511
  when Nodes::FieldDefinition
348
512
  print_field_definition(node)
349
513
  when Nodes::InterfaceTypeDefinition
350
514
  print_interface_type_definition(node)
515
+ when Nodes::InterfaceTypeExtension
516
+ print_interface_type_definition(node, extension: true)
351
517
  when Nodes::UnionTypeDefinition
352
518
  print_union_type_definition(node)
519
+ when Nodes::UnionTypeExtension
520
+ print_union_type_definition(node, extension: true)
353
521
  when Nodes::EnumTypeDefinition
354
522
  print_enum_type_definition(node)
523
+ when Nodes::EnumTypeExtension
524
+ print_enum_type_definition(node, extension: true)
355
525
  when Nodes::EnumValueDefinition
356
526
  print_enum_value_definition(node)
357
527
  when Nodes::InputObjectTypeDefinition
358
528
  print_input_object_type_definition(node)
529
+ when Nodes::InputObjectTypeExtension
530
+ print_input_object_type_definition(node, extension: true)
359
531
  when Nodes::DirectiveDefinition
360
532
  print_directive_definition(node)
361
533
  when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
362
- GraphQL::Language.serialize(node)
534
+ print_string(GraphQL::Language.serialize(node))
363
535
  when Array
364
- "[#{node.map { |v| print_node(v) }.join(", ")}]".dup
536
+ print_string("[")
537
+ node.each_with_index do |v, i|
538
+ print_node(v)
539
+ print_string(", ") if i < node.length - 1
540
+ end
541
+ print_string("]")
365
542
  when Hash
366
- "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
543
+ print_string("{")
544
+ node.each_with_index do |(k, v), i|
545
+ print_string(k)
546
+ print_string(": ")
547
+ print_node(v)
548
+ print_string(", ") if i < node.length - 1
549
+ end
550
+ print_string("}")
367
551
  else
368
- GraphQL::Language.serialize(node.to_s)
552
+ print_string(GraphQL::Language.serialize(node.to_s))
369
553
  end
370
554
  end
371
-
372
- private
373
-
374
- attr_reader :node
375
555
  end
376
556
  end
377
557
  end