graphql 1.7.7 → 1.7.8

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/enum_type.rb +1 -1
  3. data/lib/graphql/field.rb +10 -1
  4. data/lib/graphql/input_object_type.rb +3 -1
  5. data/lib/graphql/introspection/arguments_field.rb +1 -0
  6. data/lib/graphql/introspection/enum_values_field.rb +1 -0
  7. data/lib/graphql/introspection/fields_field.rb +1 -0
  8. data/lib/graphql/introspection/input_fields_field.rb +1 -0
  9. data/lib/graphql/introspection/interfaces_field.rb +1 -0
  10. data/lib/graphql/introspection/of_type_field.rb +1 -0
  11. data/lib/graphql/introspection/possible_types_field.rb +1 -0
  12. data/lib/graphql/introspection/schema_field.rb +1 -0
  13. data/lib/graphql/introspection/type_by_name_field.rb +1 -0
  14. data/lib/graphql/introspection/typename_field.rb +1 -0
  15. data/lib/graphql/language.rb +1 -0
  16. data/lib/graphql/language/document_from_schema_definition.rb +129 -37
  17. data/lib/graphql/language/generation.rb +3 -182
  18. data/lib/graphql/language/nodes.rb +12 -2
  19. data/lib/graphql/language/parser.rb +63 -55
  20. data/lib/graphql/language/parser.y +2 -1
  21. data/lib/graphql/language/printer.rb +351 -0
  22. data/lib/graphql/object_type.rb +1 -1
  23. data/lib/graphql/query/arguments.rb +27 -9
  24. data/lib/graphql/query/literal_input.rb +4 -1
  25. data/lib/graphql/schema/printer.rb +33 -266
  26. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  27. data/lib/graphql/version.rb +1 -1
  28. data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
  29. data/spec/graphql/language/generation_spec.rb +21 -186
  30. data/spec/graphql/language/nodes_spec.rb +21 -0
  31. data/spec/graphql/language/printer_spec.rb +203 -0
  32. data/spec/graphql/query/arguments_spec.rb +33 -11
  33. data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
  34. data/spec/graphql/schema/printer_spec.rb +14 -14
  35. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38483eef219e223ada69c9b3abf6be4b21b18631
4
- data.tar.gz: 6e7b06898fbc81c29dd817ee9817ae54e4a44ada
3
+ metadata.gz: d85dab3949103799bd681457cdb2fecd6ddcaddf
4
+ data.tar.gz: ed5808c8a3caba6bf7834c0c7e2299ad5597eab3
5
5
  SHA512:
6
- metadata.gz: 8c1813ee4f6758846e9f5620d1952517c9d7a3d714e265d18da05fcd68425f152afdae56f8c400fd55d4e455e03443f26d90e04fd69578d85c71b3130f5eaf0f
7
- data.tar.gz: 41480a626d5acf9db70ea864438e192bab03ec56ad89c137f9f5e63e9ada426c3fd812b9099e8f4c621e3705740fd7daf1d1f74019c632ebd19f54e62608eb90
6
+ metadata.gz: 19330668600890f1dd17e4231e5ded4a43b4cf35dc3c076b07a0b8d54449924c1967c8c9609c4ea9729beaf800c9d63280d48ce7ccefb18b0466db8b54494108
7
+ data.tar.gz: 80a05ac7f10d5c2a3727d12f4ca8f30cfa3634d8047e1d23cc15f66e1c63940c9d27e0d7d875e05d084897702d56794daf314c830785edae969d8fab0ab06399
@@ -121,7 +121,7 @@ module GraphQL
121
121
  if enum_value
122
122
  enum_value.name
123
123
  else
124
- raise(UnresolvedValueError, "Can't resolve enum #{name} for #{value}")
124
+ raise(UnresolvedValueError, "Can't resolve enum #{name} for #{value.inspect}")
125
125
  end
126
126
  end
127
127
 
@@ -131,6 +131,7 @@ module GraphQL
131
131
  :relay_nodes_field,
132
132
  :subscription_scope,
133
133
  :trace,
134
+ :introspection,
134
135
  argument: GraphQL::Define::AssignArgument
135
136
 
136
137
  ensure_defined(
@@ -138,7 +139,8 @@ module GraphQL
138
139
  :mutation, :arguments, :complexity, :function,
139
140
  :resolve, :resolve=, :lazy_resolve, :lazy_resolve=, :lazy_resolve_proc, :resolve_proc,
140
141
  :type, :type=, :name=, :property=, :hash_key=,
141
- :relay_node_field, :relay_nodes_field, :edges?, :edge_class, :subscription_scope
142
+ :relay_node_field, :relay_nodes_field, :edges?, :edge_class, :subscription_scope,
143
+ :introspection?
142
144
  )
143
145
 
144
146
  # @return [Boolean] True if this is the Relay find-by-id field
@@ -183,6 +185,7 @@ module GraphQL
183
185
  attr_accessor :arguments_class
184
186
 
185
187
  attr_writer :connection
188
+ attr_writer :introspection
186
189
 
187
190
  # @return [nil, String] Prefix for subscription names from this field
188
191
  attr_accessor :subscription_scope
@@ -217,6 +220,7 @@ module GraphQL
217
220
  @connection_max_page_size = nil
218
221
  @edge_class = nil
219
222
  @trace = nil
223
+ @introspection = false
220
224
  end
221
225
 
222
226
  def initialize_copy(other)
@@ -224,6 +228,11 @@ module GraphQL
224
228
  @arguments = other.arguments.dup
225
229
  end
226
230
 
231
+ # @return [Boolean] Is this field a predefined introspection field?
232
+ def introspection?
233
+ @introspection
234
+ end
235
+
227
236
  # Get a value for this field
228
237
  # @example resolving a field value
229
238
  # field.resolve(obj, args, ctx)
@@ -84,6 +84,7 @@ module GraphQL
84
84
 
85
85
  def coerce_non_null_input(value, ctx)
86
86
  input_values = {}
87
+ defaults_used = Set.new
87
88
 
88
89
  arguments.each do |input_key, input_field_defn|
89
90
  field_value = value[input_key]
@@ -93,10 +94,11 @@ module GraphQL
93
94
  input_values[input_key] = input_field_defn.prepare(coerced_value, ctx)
94
95
  elsif input_field_defn.default_value?
95
96
  input_values[input_key] = input_field_defn.default_value
97
+ defaults_used << input_key
96
98
  end
97
99
  end
98
100
 
99
- arguments_class.new(input_values)
101
+ arguments_class.new(input_values, defaults_used)
100
102
  end
101
103
 
102
104
  # @api private
@@ -1,6 +1,7 @@
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
4
5
  resolve ->(obj, args, ctx) {
5
6
  ctx.warden.arguments(obj)
6
7
  }
@@ -1,6 +1,7 @@
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
4
5
  argument :includeDeprecated, types.Boolean, default_value: false
5
6
  resolve ->(object, arguments, context) do
6
7
  if !object.kind.enum?
@@ -1,6 +1,7 @@
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
4
5
  argument :includeDeprecated, GraphQL::BOOLEAN_TYPE, default_value: false
5
6
  resolve ->(object, arguments, context) {
6
7
  return nil if !object.kind.fields?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::InputFieldsField = GraphQL::Field.define do
3
3
  name "inputFields"
4
+ introspection true
4
5
  type types[!GraphQL::Introspection::InputValueType]
5
6
  resolve ->(target, a, ctx) {
6
7
  if target.kind.input_object?
@@ -1,6 +1,7 @@
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
4
5
  resolve ->(target, a, ctx) {
5
6
  if target.kind == GraphQL::TypeKinds::OBJECT
6
7
  ctx.warden.interfaces(target)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  GraphQL::Introspection::OfTypeField = GraphQL::Field.define do
3
3
  name "ofType"
4
+ introspection true
4
5
  type -> { GraphQL::Introspection::TypeType }
5
6
  resolve ->(obj, args, ctx) { obj.kind.wraps? ? obj.of_type : nil }
6
7
  end
@@ -1,6 +1,7 @@
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
4
5
  resolve ->(target, args, ctx) {
5
6
  if target.kind.resolves?
6
7
  ctx.warden.possible_types(target)
@@ -4,6 +4,7 @@ module GraphQL
4
4
  SchemaField = GraphQL::Field.define do
5
5
  name("__schema")
6
6
  description("This GraphQL schema")
7
+ introspection true
7
8
  type(!GraphQL::Introspection::SchemaType)
8
9
  resolve ->(o, a, ctx) { ctx.query.schema }
9
10
  end
@@ -5,6 +5,7 @@ module GraphQL
5
5
  name("__type")
6
6
  description("A type in the GraphQL system")
7
7
  type(GraphQL::Introspection::TypeType)
8
+ introspection true
8
9
  argument :name, !types.String
9
10
  resolve ->(o, args, ctx) {
10
11
  ctx.warden.get_type(args["name"])
@@ -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