graphql 1.7.13 → 1.7.14

Sign up to get free protection for your applications and to get access to all the features.
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