graphql 1.7.13 → 1.7.14

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/argument.rb +1 -0
  3. data/lib/graphql/base_type.rb +7 -0
  4. data/lib/graphql/compatibility/query_parser_specification.rb +110 -0
  5. data/lib/graphql/directive.rb +1 -0
  6. data/lib/graphql/enum_type.rb +2 -0
  7. data/lib/graphql/execution/multiplex.rb +1 -1
  8. data/lib/graphql/field.rb +2 -0
  9. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  10. data/lib/graphql/language/lexer.rb +65 -51
  11. data/lib/graphql/language/lexer.rl +2 -0
  12. data/lib/graphql/language/nodes.rb +118 -71
  13. data/lib/graphql/language/parser.rb +701 -654
  14. data/lib/graphql/language/parser.y +14 -8
  15. data/lib/graphql/language/printer.rb +2 -2
  16. data/lib/graphql/object_type.rb +0 -5
  17. data/lib/graphql/relay/relation_connection.rb +1 -1
  18. data/lib/graphql/schema.rb +1 -0
  19. data/lib/graphql/schema/build_from_definition.rb +60 -18
  20. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  21. data/lib/graphql/unresolved_type_error.rb +3 -2
  22. data/lib/graphql/version.rb +1 -1
  23. data/spec/graphql/base_type_spec.rb +22 -0
  24. data/spec/graphql/enum_type_spec.rb +18 -5
  25. data/spec/graphql/execution/multiplex_spec.rb +1 -1
  26. data/spec/graphql/input_object_type_spec.rb +13 -0
  27. data/spec/graphql/language/nodes_spec.rb +0 -12
  28. data/spec/graphql/language/printer_spec.rb +1 -1
  29. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  30. data/spec/graphql/query_spec.rb +26 -0
  31. data/spec/graphql/relay/relation_connection_spec.rb +7 -1
  32. data/spec/graphql/schema/build_from_definition_spec.rb +59 -0
  33. data/spec/graphql/schema/printer_spec.rb +34 -0
  34. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  35. metadata +2 -2
@@ -152,12 +152,8 @@ rule
152
152
  | operation_type
153
153
  | schema_keyword
154
154
 
155
- name_list:
156
- name { return [make_node(:TypeName, name: val[0])] }
157
- | name_list name { val[0] << make_node(:TypeName, name: val[1]) }
158
-
159
155
  enum_value_definition:
160
- enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0])) }
156
+ enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0]), position_source: val[0]) }
161
157
 
162
158
  enum_value_definitions:
163
159
  enum_value_definition { return [val[0]] }
@@ -306,11 +302,21 @@ rule
306
302
 
307
303
  implements_opt:
308
304
  /* none */ { return [] }
309
- | IMPLEMENTS name_list { return val[1] }
305
+ | IMPLEMENTS AMP interfaces_list { return val[2] }
306
+ | IMPLEMENTS interfaces_list { return val[1] }
307
+ | IMPLEMENTS legacy_interfaces_list { return val[1] }
308
+
309
+ interfaces_list:
310
+ name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
311
+ | interfaces_list AMP name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
312
+
313
+ legacy_interfaces_list:
314
+ name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
315
+ | legacy_interfaces_list name { val[0] << make_node(:TypeName, name: val[1], position_source: val[1]) }
310
316
 
311
317
  input_value_definition:
312
318
  name COLON type default_value_opt directives_list_opt {
313
- return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]))
319
+ return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
314
320
  }
315
321
 
316
322
  input_value_definition_list:
@@ -323,7 +329,7 @@ rule
323
329
 
324
330
  field_definition:
325
331
  name arguments_definitions_opt COLON type directives_list_opt {
326
- return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]))
332
+ return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
327
333
  }
328
334
 
329
335
  field_definition_list:
@@ -154,7 +154,7 @@ module GraphQL
154
154
  def print_object_type_definition(object_type)
155
155
  out = print_description(object_type)
156
156
  out << "type #{object_type.name}"
157
- out << " implements " << object_type.interfaces.map(&:name).join(", ") unless object_type.interfaces.empty?
157
+ out << " implements " << object_type.interfaces.map(&:name).join(" & ") unless object_type.interfaces.empty?
158
158
  out << print_directives(object_type.directives)
159
159
  out << print_field_definitions(object_type.fields)
160
160
  end
@@ -339,7 +339,7 @@ module GraphQL
339
339
  when Hash
340
340
  "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
341
341
  else
342
- raise TypeError
342
+ GraphQL::Language.serialize(node.to_s)
343
343
  end
344
344
  end
345
345
 
@@ -102,11 +102,6 @@ module GraphQL
102
102
  dirty_ifaces.concat(interfaces)
103
103
  end
104
104
 
105
- def name=(name)
106
- GraphQL::NameValidator.validate!(name)
107
- @name = name
108
- end
109
-
110
105
  protected
111
106
 
112
107
  attr_reader :dirty_interfaces, :dirty_inherited_interfaces
@@ -27,7 +27,7 @@ module GraphQL
27
27
  if first
28
28
  paged_nodes.length >= first && sliced_nodes_count > first
29
29
  elsif GraphQL::Relay::ConnectionType.bidirectional_pagination && last
30
- sliced_nodes_count > last
30
+ sliced_nodes_count >= last
31
31
  else
32
32
  false
33
33
  end
@@ -80,6 +80,7 @@ module GraphQL
80
80
  :orphan_types, :directives,
81
81
  :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
82
82
  :cursor_encoder,
83
+ :ast_node,
83
84
  :raise_definition_error
84
85
 
85
86
  # Single, long-lived instance of the provided subscriptions class, if there is one.
@@ -107,6 +107,8 @@ module GraphQL
107
107
  directives directives.values
108
108
  end
109
109
 
110
+ schema.ast_node = schema_definition if schema_definition
111
+
110
112
  schema
111
113
  end
112
114
 
@@ -117,18 +119,26 @@ module GraphQL
117
119
  NullScalarCoerce = ->(val, _ctx) { val }
118
120
 
119
121
  def build_enum_type(enum_type_definition, type_resolver)
120
- GraphQL::EnumType.define(
122
+ enum = GraphQL::EnumType.define(
121
123
  name: enum_type_definition.name,
122
124
  description: enum_type_definition.description,
123
125
  values: enum_type_definition.values.map do |enum_value_definition|
124
- EnumType::EnumValue.define(
126
+ value = EnumType::EnumValue.define(
125
127
  name: enum_value_definition.name,
126
128
  value: enum_value_definition.name,
127
129
  deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
128
130
  description: enum_value_definition.description,
129
131
  )
132
+
133
+ value.ast_node = enum_value_definition
134
+
135
+ value
130
136
  end
131
137
  )
138
+
139
+ enum.ast_node = enum_type_definition
140
+
141
+ enum
132
142
  end
133
143
 
134
144
  def build_deprecation_reason(directives)
@@ -148,6 +158,8 @@ module GraphQL
148
158
  coerce: NullScalarCoerce,
149
159
  )
150
160
 
161
+ scalar_type.ast_node = scalar_type_definition
162
+
151
163
  if default_resolve.respond_to?(:coerce_input)
152
164
  scalar_type = scalar_type.redefine(
153
165
  coerce_input: ->(val, ctx) { default_resolve.coerce_input(scalar_type, val, ctx) },
@@ -159,11 +171,15 @@ module GraphQL
159
171
  end
160
172
 
161
173
  def build_union_type(union_type_definition, type_resolver)
162
- GraphQL::UnionType.define(
174
+ union = GraphQL::UnionType.define(
163
175
  name: union_type_definition.name,
164
176
  description: union_type_definition.description,
165
177
  possible_types: union_type_definition.types.map{ |type_name| type_resolver.call(type_name) },
166
178
  )
179
+
180
+ union.ast_node = union_type_definition
181
+
182
+ union
167
183
  end
168
184
 
169
185
  def build_object_type(object_type_definition, type_resolver, default_resolve:)
@@ -175,14 +191,20 @@ module GraphQL
175
191
  fields: Hash[build_fields(object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)],
176
192
  interfaces: object_type_definition.interfaces.map{ |interface_name| type_resolver.call(interface_name) },
177
193
  )
194
+ type_def.ast_node = object_type_definition
195
+ type_def
178
196
  end
179
197
 
180
198
  def build_input_object_type(input_object_type_definition, type_resolver)
181
- GraphQL::InputObjectType.define(
199
+ input = GraphQL::InputObjectType.define(
182
200
  name: input_object_type_definition.name,
183
201
  description: input_object_type_definition.description,
184
202
  arguments: Hash[build_input_arguments(input_object_type_definition, type_resolver)],
185
203
  )
204
+
205
+ input.ast_node = input_object_type_definition
206
+
207
+ input
186
208
  end
187
209
 
188
210
  def build_default_value(default_value)
@@ -208,25 +230,33 @@ module GraphQL
208
230
  kwargs[:default_value] = build_default_value(input_argument.default_value)
209
231
  end
210
232
 
233
+ argument = GraphQL::Argument.define(
234
+ name: input_argument.name,
235
+ type: type_resolver.call(input_argument.type),
236
+ description: input_argument.description,
237
+ **kwargs,
238
+ )
239
+
240
+ argument.ast_node = input_object_type_definition
241
+
211
242
  [
212
243
  input_argument.name,
213
- GraphQL::Argument.define(
214
- name: input_argument.name,
215
- type: type_resolver.call(input_argument.type),
216
- description: input_argument.description,
217
- **kwargs,
218
- )
244
+ argument
219
245
  ]
220
246
  end
221
247
  end
222
248
 
223
249
  def build_directive(directive_definition, type_resolver)
224
- GraphQL::Directive.define(
250
+ directive = GraphQL::Directive.define(
225
251
  name: directive_definition.name,
226
252
  description: directive_definition.description,
227
253
  arguments: Hash[build_directive_arguments(directive_definition, type_resolver)],
228
254
  locations: directive_definition.locations.map(&:to_sym),
229
255
  )
256
+
257
+ directive.ast_node = directive_definition
258
+
259
+ directive
230
260
  end
231
261
 
232
262
  def build_directive_arguments(directive_definition, type_resolver)
@@ -237,24 +267,32 @@ module GraphQL
237
267
  kwargs[:default_value] = build_default_value(directive_argument.default_value)
238
268
  end
239
269
 
270
+ argument = GraphQL::Argument.define(
271
+ name: directive_argument.name,
272
+ type: type_resolver.call(directive_argument.type),
273
+ description: directive_argument.description,
274
+ **kwargs,
275
+ )
276
+
277
+ argument.ast_node = directive_argument
278
+
240
279
  [
241
280
  directive_argument.name,
242
- GraphQL::Argument.define(
243
- name: directive_argument.name,
244
- type: type_resolver.call(directive_argument.type),
245
- description: directive_argument.description,
246
- **kwargs,
247
- )
281
+ argument
248
282
  ]
249
283
  end
250
284
  end
251
285
 
252
286
  def build_interface_type(interface_type_definition, type_resolver)
253
- GraphQL::InterfaceType.define(
287
+ interface = GraphQL::InterfaceType.define(
254
288
  name: interface_type_definition.name,
255
289
  description: interface_type_definition.description,
256
290
  fields: Hash[build_fields(interface_type_definition.fields, type_resolver, default_resolve: nil)],
257
291
  )
292
+
293
+ interface.ast_node = interface_type_definition
294
+
295
+ interface
258
296
  end
259
297
 
260
298
  def build_fields(field_definitions, type_resolver, default_resolve:)
@@ -273,6 +311,8 @@ module GraphQL
273
311
  **kwargs,
274
312
  )
275
313
 
314
+ arg.ast_node = argument
315
+
276
316
  [argument.name, arg]
277
317
  end]
278
318
 
@@ -285,6 +325,8 @@ module GraphQL
285
325
  deprecation_reason: build_deprecation_reason(field_definition.directives),
286
326
  )
287
327
 
328
+ field.ast_node = field_definition
329
+
288
330
  type_name = resolve_type_name(field_definition.type)
289
331
  field.connection = type_name.end_with?("Connection")
290
332
  [field_definition.name, field]
@@ -39,7 +39,7 @@ module GraphQL
39
39
  # })
40
40
  #
41
41
  # payload = {
42
- # result: result.subscription? ? nil : result.to_h,
42
+ # result: result.subscription? ? {data: nil} : result.to_h,
43
43
  # more: result.subscription?,
44
44
  # }
45
45
  #
@@ -26,8 +26,9 @@ module GraphQL
26
26
  @possible_types = possible_types
27
27
  message = "The value from \"#{field.name}\" on \"#{parent_type}\" could not be resolved to \"#{field.type}\". " \
28
28
  "(Received: `#{resolved_type.inspect}`, Expected: [#{possible_types.map(&:inspect).join(", ")}]) " \
29
- "Make sure you have defined a `type_from_object` proc on your schema and that value `#{value.inspect}` " \
30
- "gets resolved to a valid type."
29
+ "Make sure you have defined a `resolve_type` proc on your schema and that value `#{value.inspect}` " \
30
+ "gets resolved to a valid type. You may need to add your type to `orphan_types` if it implements an " \
31
+ "interface but isn't a return type of any other field."
31
32
  super(message)
32
33
  end
33
34
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.7.13"
3
+ VERSION = "1.7.14"
4
4
  end
@@ -28,6 +28,28 @@ describe GraphQL::BaseType do
28
28
  assert_equal ["Cheese"], Dummy::CheeseType.metadata[:class_names]
29
29
  end
30
30
 
31
+ describe "#name" do
32
+ describe "when containing spaces" do
33
+ BaseNameSpaceTest = GraphQL::BaseType.define do
34
+ name "Some Invalid Name"
35
+ end
36
+
37
+ it "is invalid" do
38
+ assert_raises(GraphQL::InvalidNameError) { BaseNameSpaceTest.name }
39
+ end
40
+ end
41
+
42
+ describe "when containing colons" do
43
+ BaseNameColonsTest = GraphQL::BaseType.define do
44
+ name "Some::Invalid::Name"
45
+ end
46
+
47
+ it 'is invalid' do
48
+ assert_raises(GraphQL::InvalidNameError) { BaseNameColonsTest.name }
49
+ end
50
+ end
51
+ end
52
+
31
53
  describe "#dup" do
32
54
  let(:obj_type) {
33
55
  GraphQL::ObjectType.define do
@@ -37,21 +37,34 @@ describe GraphQL::EnumType do
37
37
  end
38
38
  end
39
39
 
40
- describe "invalid names" do
41
- it "rejects names with a space" do
40
+ describe "invalid values" do
41
+ it "rejects value names with a space" do
42
42
  assert_raises(GraphQL::InvalidNameError) {
43
- InvalidEnumTest = GraphQL::EnumType.define do
44
- name "InvalidEnumTest"
43
+ InvalidEnumValueTest = GraphQL::EnumType.define do
44
+ name "InvalidEnumValueTest"
45
45
 
46
46
  value("SPACE IN VALUE", "Invalid enum because it contains spaces", value: 1)
47
47
  end
48
48
 
49
49
  # Force evaluation
50
- InvalidEnumTest.name
50
+ InvalidEnumValueTest.name
51
51
  }
52
52
  end
53
53
  end
54
54
 
55
+ describe "invalid name" do
56
+ it "reject names with invalid format" do
57
+ assert_raises(GraphQL::InvalidNameError) do
58
+ InvalidEnumNameTest = GraphQL::EnumType.define do
59
+ name "Some::Invalid::Name"
60
+ end
61
+
62
+ # Force evaluation
63
+ InvalidEnumNameTest.name
64
+ end
65
+ end
66
+ end
67
+
55
68
  describe "values that are Arrays" do
56
69
  let(:schema) {
57
70
  enum = GraphQL::EnumType.define do
@@ -176,7 +176,7 @@ describe GraphQL::Execution::Multiplex do
176
176
  assert_raises(GraphQL::Error) do
177
177
  InspectSchema.execute("{ raiseError }")
178
178
  end
179
- unhandled_err_json = 'null'
179
+ unhandled_err_json = '{}'
180
180
  assert_equal unhandled_err_json, InspectQueryInstrumentation.last_json
181
181
  end
182
182
  end
@@ -218,6 +218,19 @@ describe GraphQL::InputObjectType do
218
218
  assert_equal(expected, actual)
219
219
  end
220
220
  end
221
+
222
+ describe 'with invalid name' do
223
+ it 'raises the correct error' do
224
+ assert_raises(GraphQL::InvalidNameError) do
225
+ InvalidInputTest = GraphQL::InputObjectType.define do
226
+ name "Some::Invalid Name"
227
+ end
228
+
229
+ # Force evaluation
230
+ InvalidInputTest.name
231
+ end
232
+ end
233
+ end
221
234
  end
222
235
  end
223
236
 
@@ -2,18 +2,6 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe GraphQL::Language::Nodes::AbstractNode do
5
- describe "child and scalar attributes" do
6
- it "are inherited by node subclasses" do
7
- subclassed_directive = Class.new(GraphQL::Language::Nodes::Directive)
8
-
9
- assert_equal GraphQL::Language::Nodes::Directive.scalar_attributes,
10
- subclassed_directive.scalar_attributes
11
-
12
- assert_equal GraphQL::Language::Nodes::Directive.child_attributes,
13
- subclassed_directive.child_attributes
14
- end
15
- end
16
-
17
5
  describe "#filename" do
18
6
  it "is set after .parse_file" do
19
7
  filename = "spec/support/parser/filename_example.graphql"
@@ -115,7 +115,7 @@ describe GraphQL::Language::Printer do
115
115
  # Union description
116
116
  union AnnotatedUnion @onUnion = A | B
117
117
 
118
- type Foo implements Bar {
118
+ type Foo implements Bar & AnnotatedInterface {
119
119
  one: Type
120
120
  two(argument: InputType!): Type
121
121
  three(argument: InputType, other: String): Int
@@ -88,7 +88,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
88
88
  err = assert_raises(GraphQL::UnresolvedTypeError) { result }
89
89
  expected_message = "The value from \"resolvesToNilInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
90
90
  "(Received: `nil`, Expected: [SomeObject]) " \
91
- "Make sure you have defined a `type_from_object` proc on your schema and that value `1337` " \
91
+ "Make sure you have defined a `resolve_type` proc on your schema and that value `1337` " \
92
92
  "gets resolved to a valid type."
93
93
  assert_equal expected_message, err.message
94
94
  end
@@ -105,7 +105,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
105
105
  err = assert_raises(GraphQL::UnresolvedTypeError) { result }
106
106
  expected_message = "The value from \"resolvesToWrongTypeInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
107
107
  "(Received: `OtherObject`, Expected: [SomeObject]) " \
108
- "Make sure you have defined a `type_from_object` proc on your schema and that value `:something` " \
108
+ "Make sure you have defined a `resolve_type` proc on your schema and that value `:something` " \
109
109
  "gets resolved to a valid type."
110
110
  assert_equal expected_message, err.message
111
111
  end