graphql 1.8.0.pre2 → 1.8.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +1 -1
  3. data/lib/graphql/deprecated_dsl.rb +2 -0
  4. data/lib/graphql/enum_type.rb +1 -1
  5. data/lib/graphql/field.rb +10 -1
  6. data/lib/graphql/input_object_type.rb +3 -1
  7. data/lib/graphql/introspection.rb +3 -10
  8. data/lib/graphql/introspection/base_object.rb +15 -0
  9. data/lib/graphql/introspection/directive_location_enum.rb +11 -7
  10. data/lib/graphql/introspection/directive_type.rb +23 -16
  11. data/lib/graphql/introspection/dynamic_fields.rb +11 -0
  12. data/lib/graphql/introspection/entry_points.rb +29 -0
  13. data/lib/graphql/introspection/enum_value_type.rb +16 -11
  14. data/lib/graphql/introspection/field_type.rb +21 -12
  15. data/lib/graphql/introspection/input_value_type.rb +26 -23
  16. data/lib/graphql/introspection/schema_field.rb +7 -2
  17. data/lib/graphql/introspection/schema_type.rb +36 -22
  18. data/lib/graphql/introspection/type_by_name_field.rb +10 -2
  19. data/lib/graphql/introspection/type_kind_enum.rb +10 -6
  20. data/lib/graphql/introspection/type_type.rb +85 -23
  21. data/lib/graphql/introspection/typename_field.rb +1 -0
  22. data/lib/graphql/language.rb +1 -0
  23. data/lib/graphql/language/document_from_schema_definition.rb +129 -37
  24. data/lib/graphql/language/generation.rb +3 -182
  25. data/lib/graphql/language/nodes.rb +12 -2
  26. data/lib/graphql/language/parser.rb +63 -55
  27. data/lib/graphql/language/parser.y +2 -1
  28. data/lib/graphql/language/printer.rb +351 -0
  29. data/lib/graphql/object_type.rb +1 -1
  30. data/lib/graphql/query.rb +1 -1
  31. data/lib/graphql/query/arguments.rb +24 -8
  32. data/lib/graphql/query/context.rb +3 -0
  33. data/lib/graphql/query/literal_input.rb +4 -1
  34. data/lib/graphql/railtie.rb +28 -6
  35. data/lib/graphql/schema.rb +42 -7
  36. data/lib/graphql/schema/enum.rb +1 -0
  37. data/lib/graphql/schema/field.rb +26 -5
  38. data/lib/graphql/schema/field/dynamic_resolve.rb +18 -9
  39. data/lib/graphql/schema/input_object.rb +2 -2
  40. data/lib/graphql/schema/introspection_system.rb +93 -0
  41. data/lib/graphql/schema/late_bound_type.rb +32 -0
  42. data/lib/graphql/schema/member.rb +21 -1
  43. data/lib/graphql/schema/member/build_type.rb +8 -6
  44. data/lib/graphql/schema/member/has_fields.rb +1 -1
  45. data/lib/graphql/schema/member/instrumentation.rb +3 -1
  46. data/lib/graphql/schema/member/list_type_proxy.rb +4 -0
  47. data/lib/graphql/schema/member/non_null_type_proxy.rb +4 -0
  48. data/lib/graphql/schema/object.rb +2 -1
  49. data/lib/graphql/schema/printer.rb +33 -266
  50. data/lib/graphql/schema/traversal.rb +74 -6
  51. data/lib/graphql/schema/validation.rb +3 -2
  52. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
  53. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  54. data/lib/graphql/upgrader/member.rb +463 -63
  55. data/lib/graphql/version.rb +1 -1
  56. data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
  57. data/spec/fixtures/upgrader/blame_range.transformed.rb +31 -0
  58. data/spec/fixtures/upgrader/subscribable.original.rb +51 -0
  59. data/spec/fixtures/upgrader/subscribable.transformed.rb +46 -0
  60. data/spec/fixtures/upgrader/type_x.original.rb +35 -0
  61. data/spec/fixtures/upgrader/type_x.transformed.rb +35 -0
  62. data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
  63. data/spec/graphql/language/generation_spec.rb +21 -186
  64. data/spec/graphql/language/nodes_spec.rb +21 -0
  65. data/spec/graphql/language/printer_spec.rb +203 -0
  66. data/spec/graphql/query/arguments_spec.rb +14 -4
  67. data/spec/graphql/query/context_spec.rb +17 -0
  68. data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
  69. data/spec/graphql/schema/field_spec.rb +14 -0
  70. data/spec/graphql/schema/introspection_system_spec.rb +39 -0
  71. data/spec/graphql/schema/object_spec.rb +12 -1
  72. data/spec/graphql/schema/printer_spec.rb +14 -14
  73. data/spec/graphql/tracing/platform_tracing_spec.rb +2 -2
  74. data/spec/graphql/upgrader/member_spec.rb +274 -62
  75. data/spec/support/jazz.rb +75 -3
  76. metadata +38 -9
  77. data/lib/graphql/introspection/arguments_field.rb +0 -7
  78. data/lib/graphql/introspection/enum_values_field.rb +0 -18
  79. data/lib/graphql/introspection/fields_field.rb +0 -13
  80. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  81. data/lib/graphql/introspection/interfaces_field.rb +0 -11
  82. data/lib/graphql/introspection/of_type_field.rb +0 -6
  83. data/lib/graphql/introspection/possible_types_field.rb +0 -11
@@ -4,10 +4,18 @@ module GraphQL
4
4
  TypeByNameField = GraphQL::Field.define do
5
5
  name("__type")
6
6
  description("A type in the GraphQL system")
7
- type(GraphQL::Introspection::TypeType)
7
+ introspection true
8
+ type(GraphQL::Schema::LateBoundType.new("__Type"))
8
9
  argument :name, !types.String
9
10
  resolve ->(o, args, ctx) {
10
- ctx.warden.get_type(args["name"])
11
+ type = ctx.warden.get_type(args["name"])
12
+ if type
13
+ # Apply wrapping manually since this field isn't wrapped by instrumentation
14
+ type_type = ctx.schema.introspection_system.type_type
15
+ type_type.metadata[:object_class].new(type, ctx)
16
+ else
17
+ nil
18
+ end
11
19
  }
12
20
  end
13
21
  end
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Introspection::TypeKindEnum = GraphQL::EnumType.define do
3
- name "__TypeKind"
4
- description "An enum describing what kind of type a given `__Type` is."
5
- GraphQL::TypeKinds::TYPE_KINDS.each do |type_kind|
6
- value(type_kind.name, type_kind.description)
2
+ module GraphQL
3
+ module Introspection
4
+ class TypeKindEnum < GraphQL::Schema::Enum
5
+ graphql_name "__TypeKind"
6
+ description "An enum describing what kind of type a given `__Type` is."
7
+ GraphQL::TypeKinds::TYPE_KINDS.each do |type_kind|
8
+ value(type_kind.name, type_kind.description)
9
+ end
10
+ introspection true
11
+ end
7
12
  end
8
- introspection true
9
13
  end
@@ -1,26 +1,88 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Introspection::TypeType = GraphQL::ObjectType.define do
3
- name "__Type"
4
- description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
5
- "GraphQL as represented by the `__TypeKind` enum.\n\n"\
6
- "Depending on the kind of a type, certain fields describe information about that type. "\
7
- "Scalar types provide no information beyond a name and description, while "\
8
- "Enum types provide their values. Object and Interface types provide the fields "\
9
- "they describe. Abstract types, Union and Interface, provide the Object types "\
10
- "possible at runtime. List and NonNull types compose other types."
11
-
12
- field :kind do
13
- type !GraphQL::Introspection::TypeKindEnum
14
- resolve ->(target, a, c) { target.kind.name }
15
- end
2
+ module GraphQL
3
+ module Introspection
4
+ class TypeType < GraphQL::Schema::Object
5
+ graphql_name "__Type"
6
+ description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
7
+ "GraphQL as represented by the `__TypeKind` enum.\n\n"\
8
+ "Depending on the kind of a type, certain fields describe information about that type. "\
9
+ "Scalar types provide no information beyond a name and description, while "\
10
+ "Enum types provide their values. Object and Interface types provide the fields "\
11
+ "they describe. Abstract types, Union and Interface, provide the Object types "\
12
+ "possible at runtime. List and NonNull types compose other types."
13
+
14
+ field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
+ field :name, String, null: true
16
+ field :description, String, null: true
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], null: true do
18
+ argument :include_deprecated, Boolean, required: false, default_value: false
19
+ end
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], null: true do
23
+ argument :include_deprecated, Boolean, required: false, default_value: false
24
+ end
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true
26
+ field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
27
+ introspection true
28
+
29
+ def kind
30
+ @object.kind.name
31
+ end
32
+
33
+ def enum_values(include_deprecated:)
34
+ if !@object.kind.enum?
35
+ nil
36
+ else
37
+ enum_values = @context.warden.enum_values(@object)
38
+
39
+ if !include_deprecated
40
+ enum_values = enum_values.select {|f| !f.deprecation_reason }
41
+ end
42
+
43
+ enum_values
44
+ end
45
+ end
16
46
 
17
- field :name, types.String
18
- field :description, types.String
19
- field :fields, GraphQL::Introspection::FieldsField
20
- field :interfaces, GraphQL::Introspection::InterfacesField
21
- field :possibleTypes, GraphQL::Introspection::PossibleTypesField
22
- field :enumValues, GraphQL::Introspection::EnumValuesField
23
- field :inputFields, GraphQL::Introspection::InputFieldsField
24
- field :ofType, GraphQL::Introspection::OfTypeField
25
- introspection true
47
+ def interfaces
48
+ if @object.kind == GraphQL::TypeKinds::OBJECT
49
+ @context.warden.interfaces(@object)
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ def input_fields
56
+ if @object.kind.input_object?
57
+ @context.warden.arguments(@object)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ def possible_types
64
+ if @object.kind.resolves?
65
+ @context.warden.possible_types(@object)
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ def fields(include_deprecated:)
72
+ if !@object.kind.fields?
73
+ nil
74
+ else
75
+ fields = @context.warden.fields(@object)
76
+ if !include_deprecated
77
+ fields = fields.select {|f| !f.deprecation_reason }
78
+ end
79
+ fields.sort_by(&:name)
80
+ end
81
+ end
82
+
83
+ def of_type
84
+ @object.kind.wraps? ? @object.of_type : nil
85
+ end
86
+ end
87
+ end
26
88
  end
@@ -5,6 +5,7 @@ module GraphQL
5
5
  name "__typename"
6
6
  description "The name of this type"
7
7
  type -> { !GraphQL::STRING_TYPE }
8
+ introspection true
8
9
  resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
9
10
  end
10
11
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/language/printer"
2
3
  require "graphql/language/definition_slice"
3
4
  require "graphql/language/document_from_schema_definition"
4
5
  require "graphql/language/generation"
@@ -6,10 +6,28 @@ module GraphQL
6
6
  # {GraphQL::Language::DocumentFromSchemaDefinition} is used to convert a {GraphQL::Schema} object
7
7
  # To a {GraphQL::Language::Document} AST node.
8
8
  #
9
+ # @param context [Hash]
10
+ # @param only [<#call(member, ctx)>]
11
+ # @param except [<#call(member, ctx)>]
12
+ # @param include_introspection_types [Boolean] Whether or not to include introspection types in the AST
13
+ # @param include_built_in_scalars [Boolean] Whether or not to include built in scalars in the AST
14
+ # @param include_built_in_directives [Boolean] Whether or not to include built in diirectives in the AST
9
15
  class DocumentFromSchemaDefinition
10
- def initialize(schema)
16
+ def initialize(
17
+ schema, context: nil, only: nil, except: nil, include_introspection_types: false,
18
+ include_built_in_directives: false, include_built_in_scalars: false, always_include_schema: false
19
+ )
11
20
  @schema = schema
12
- @types = GraphQL::Schema::Traversal.new(schema, introspection: true).type_map.values
21
+ @always_include_schema = always_include_schema
22
+ @include_introspection_types = include_introspection_types
23
+ @include_built_in_scalars = include_built_in_scalars
24
+ @include_built_in_directives = include_built_in_directives
25
+
26
+ @warden = GraphQL::Schema::Warden.new(
27
+ GraphQL::Filter.new(only: only, except: except),
28
+ schema: @schema,
29
+ context: context,
30
+ )
13
31
  end
14
32
 
15
33
  def document
@@ -18,47 +36,46 @@ module GraphQL
18
36
  )
19
37
  end
20
38
 
21
- protected
22
-
23
- def build_schema_node(schema)
24
- schema_node = GraphQL::Language::Nodes::SchemaDefinition.new(
25
- query: schema.query.name
39
+ def build_schema_node
40
+ GraphQL::Language::Nodes::SchemaDefinition.new(
41
+ query: warden.root_type_for_operation("query"),
42
+ mutation: warden.root_type_for_operation("mutation"),
43
+ subscription: warden.root_type_for_operation("subscription")
26
44
  )
27
-
28
- if schema.mutation
29
- schema_node.mutation = schema.mutation.name
30
- end
31
-
32
- if schema.subscription
33
- schema_node.subscription = schema.subscription.name
34
- end
35
-
36
- schema_node
37
45
  end
38
46
 
39
47
  def build_object_type_node(object_type)
40
48
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
41
49
  name: object_type.name,
42
- interfaces: object_type.interfaces.map { |iface| build_type_name_node(iface) },
43
- fields: build_field_nodes(object_type.fields.values),
50
+ interfaces: warden.interfaces(object_type).sort_by(&:name).map { |iface| build_type_name_node(iface) },
51
+ fields: build_field_nodes(warden.fields(object_type)),
44
52
  description: object_type.description,
45
53
  )
46
54
  end
47
55
 
48
56
  def build_field_node(field)
49
- GraphQL::Language::Nodes::FieldDefinition.new(
57
+ field_node = GraphQL::Language::Nodes::FieldDefinition.new(
50
58
  name: field.name,
51
- arguments: build_argument_nodes(field.arguments.values),
59
+ arguments: build_argument_nodes(warden.arguments(field)),
52
60
  type: build_type_name_node(field.type),
53
61
  description: field.description,
54
62
  )
63
+
64
+ if field.deprecation_reason
65
+ field_node.directives << GraphQL::Language::Nodes::Directive.new(
66
+ name: GraphQL::Directive::DeprecatedDirective.name,
67
+ arguments: [GraphQL::Language::Nodes::Argument.new(name: "reason", value: field.deprecation_reason)]
68
+ )
69
+ end
70
+
71
+ field_node
55
72
  end
56
73
 
57
74
  def build_union_type_node(union_type)
58
75
  GraphQL::Language::Nodes::UnionTypeDefinition.new(
59
76
  name: union_type.name,
60
77
  description: union_type.description,
61
- types: union_type.possible_types.map { |type| build_type_name_node(type) }
78
+ types: warden.possible_types(union_type).sort_by(&:name).map { |type| build_type_name_node(type) }
62
79
  )
63
80
  end
64
81
 
@@ -66,14 +83,14 @@ module GraphQL
66
83
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
67
84
  name: interface_type.name,
68
85
  description: interface_type.description,
69
- fields: build_field_nodes(interface_type.fields.values)
86
+ fields: build_field_nodes(warden.fields(interface_type))
70
87
  )
71
88
  end
72
89
 
73
90
  def build_enum_type_node(enum_type)
74
91
  GraphQL::Language::Nodes::EnumTypeDefinition.new(
75
92
  name: enum_type.name,
76
- values: enum_type.values.values.map do |enum_value|
93
+ values: warden.enum_values(enum_type).sort_by(&:name).map do |enum_value|
77
94
  build_enum_value_node(enum_value)
78
95
  end,
79
96
  description: enum_type.description,
@@ -81,10 +98,19 @@ module GraphQL
81
98
  end
82
99
 
83
100
  def build_enum_value_node(enum_value)
84
- GraphQL::Language::Nodes::EnumValueDefinition.new(
101
+ enum_value_node = GraphQL::Language::Nodes::EnumValueDefinition.new(
85
102
  name: enum_value.name,
86
103
  description: enum_value.description,
87
104
  )
105
+
106
+ if enum_value.deprecation_reason
107
+ enum_value_node.directives << GraphQL::Language::Nodes::Directive.new(
108
+ name: GraphQL::Directive::DeprecatedDirective.name,
109
+ arguments: [GraphQL::Language::Nodes::Argument.new(name: "reason", value: enum_value.deprecation_reason)]
110
+ )
111
+ end
112
+
113
+ enum_value_node
88
114
  end
89
115
 
90
116
  def build_scalar_type_node(scalar_type)
@@ -95,18 +121,23 @@ module GraphQL
95
121
  end
96
122
 
97
123
  def build_argument_node(argument)
98
- GraphQL::Language::Nodes::InputValueDefinition.new(
124
+ argument_node = GraphQL::Language::Nodes::InputValueDefinition.new(
99
125
  name: argument.name,
100
126
  description: argument.description,
101
127
  type: build_type_name_node(argument.type),
102
- default_value: argument.default_value,
103
128
  )
129
+
130
+ if argument.default_value?
131
+ argument_node.default_value = build_default_value(argument.default_value, argument.type)
132
+ end
133
+
134
+ argument_node
104
135
  end
105
136
 
106
137
  def build_input_object_node(input_object)
107
138
  GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
108
139
  name: input_object.name,
109
- fields: build_argument_nodes(input_object.arguments.values),
140
+ fields: build_argument_nodes(warden.arguments(input_object)),
110
141
  description: input_object.description,
111
142
  )
112
143
  end
@@ -114,7 +145,7 @@ module GraphQL
114
145
  def build_directive_node(directive)
115
146
  GraphQL::Language::Nodes::DirectiveDefinition.new(
116
147
  name: directive.name,
117
- arguments: build_argument_nodes(directive.arguments.values),
148
+ arguments: build_argument_nodes(warden.arguments(directive)),
118
149
  locations: directive.locations.map(&:to_s),
119
150
  description: directive.description,
120
151
  )
@@ -135,6 +166,35 @@ module GraphQL
135
166
  end
136
167
  end
137
168
 
169
+ def build_default_value(default_value, type)
170
+ if default_value.nil?
171
+ return GraphQL::Language::Nodes::NullValue.new(name: "null")
172
+ end
173
+
174
+ case type
175
+ when GraphQL::ScalarType
176
+ default_value
177
+ when EnumType
178
+ GraphQL::Language::Nodes::Enum.new(name: type.coerce_isolated_result(default_value))
179
+ when InputObjectType
180
+ GraphQL::Language::Nodes::InputObject.new(
181
+ arguments: default_value.to_h.map do |arg_name, arg_value|
182
+ arg_type = type.input_fields.fetch(arg_name.to_s).type
183
+ GraphQL::Language::Nodes::Argument.new(
184
+ name: arg_name,
185
+ value: build_default_value(arg_value, arg_type)
186
+ )
187
+ end
188
+ )
189
+ when NonNullType
190
+ build_default_value(default_value, type.of_type)
191
+ when ListType
192
+ default_value.to_a.map { |v| build_default_value(v, type.of_type) }
193
+ else
194
+ raise NotImplementedError, "Unexpected default value type #{type.inspect}"
195
+ end
196
+ end
197
+
138
198
  def build_type_definition_node(type)
139
199
  case type
140
200
  when GraphQL::ObjectType
@@ -155,31 +215,63 @@ module GraphQL
155
215
  end
156
216
 
157
217
  def build_argument_nodes(arguments)
158
- arguments.map { |arg| build_argument_node(arg) }
218
+ arguments
219
+ .map { |arg| build_argument_node(arg) }
220
+ .sort_by(&:name)
159
221
  end
160
222
 
161
223
  def build_directive_nodes(directives)
162
- directives.map { |directive| build_directive_node(directive) }
224
+ if !include_built_in_directives
225
+ directives = directives.reject { |directive| directive.default_directive? }
226
+ end
227
+
228
+ directives
229
+ .map { |directive| build_directive_node(directive) }
230
+ .sort_by(&:name)
163
231
  end
164
232
 
165
233
  def build_definition_nodes
166
- definitions = build_type_definition_nodes(types)
167
- definitions += build_directive_nodes(schema.directives.values)
168
- definitions << build_schema_node(schema)
234
+ definitions = []
235
+ definitions << build_schema_node if include_schema_node?
236
+ definitions += build_directive_nodes(warden.directives)
237
+ definitions += build_type_definition_nodes(warden.types)
169
238
  definitions
170
239
  end
171
240
 
172
241
  def build_type_definition_nodes(types)
173
- types.map { |type| build_type_definition_node(type) }
242
+ if !include_introspection_types
243
+ types = types.reject { |type| type.introspection? }
244
+ end
245
+
246
+ if !include_built_in_scalars
247
+ types = types.reject { |type| type.default_scalar? }
248
+ end
249
+
250
+ types
251
+ .map { |type| build_type_definition_node(type) }
252
+ .sort_by(&:name)
174
253
  end
175
254
 
176
255
  def build_field_nodes(fields)
177
- fields.map { |field| build_field_node(field) }
256
+ fields
257
+ .map { |field| build_field_node(field) }
258
+ .sort_by(&:name)
178
259
  end
179
260
 
180
261
  private
181
262
 
182
- attr_reader :schema, :types
263
+ def include_schema_node?
264
+ always_include_schema || !schema_respects_root_name_conventions?(schema)
265
+ end
266
+
267
+ def schema_respects_root_name_conventions?(schema)
268
+ (schema.query.nil? || schema.query.name == 'Query') &&
269
+ (schema.mutation.nil? || schema.mutation.name == 'Mutation') &&
270
+ (schema.subscription.nil? || schema.subscription.name == 'Subscription')
271
+ end
272
+
273
+ attr_reader :schema, :warden, :always_include_schema,
274
+ :include_introspection_types, :include_built_in_directives, :include_built_in_scalars
183
275
  end
184
276
  end
185
277
  end
@@ -14,189 +14,10 @@ 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
17
18
  # @return [String] Valid GraphQL for `node`
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 << "}"
19
+ def generate(node, indent: "", printer: GraphQL::Language::Printer.new)
20
+ printer.print(node, indent: indent)
200
21
  end
201
22
  end
202
23
  end