graphql 1.8.7 → 1.8.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/enum_type.rb +4 -0
  3. data/lib/graphql/execution/multiplex.rb +1 -1
  4. data/lib/graphql/schema/argument.rb +1 -0
  5. data/lib/graphql/schema/enum_value.rb +1 -0
  6. data/lib/graphql/schema/field.rb +1 -0
  7. data/lib/graphql/schema/interface.rb +1 -0
  8. data/lib/graphql/schema/member.rb +2 -0
  9. data/lib/graphql/schema/member/has_path.rb +25 -0
  10. data/lib/graphql/schema/relay_classic_mutation.rb +3 -9
  11. data/lib/graphql/schema/resolver.rb +25 -5
  12. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -2
  13. data/lib/graphql/upgrader/member.rb +5 -0
  14. data/lib/graphql/version.rb +1 -1
  15. data/spec/dummy/Gemfile +1 -1
  16. data/spec/graphql/enum_type_spec.rb +5 -0
  17. data/spec/graphql/execution/execute_spec.rb +1 -1
  18. data/spec/graphql/execution/multiplex_spec.rb +28 -1
  19. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -0
  20. data/spec/graphql/schema/argument_spec.rb +5 -1
  21. data/spec/graphql/schema/enum_spec.rb +7 -0
  22. data/spec/graphql/schema/enum_value_spec.rb +11 -0
  23. data/spec/graphql/schema/field_spec.rb +7 -0
  24. data/spec/graphql/schema/input_object_spec.rb +11 -0
  25. data/spec/graphql/schema/interface_spec.rb +6 -0
  26. data/spec/graphql/schema/object_spec.rb +6 -0
  27. data/spec/graphql/schema/relay_classic_mutation_spec.rb +71 -0
  28. data/spec/graphql/schema/resolver_spec.rb +72 -8
  29. data/spec/graphql/schema/scalar_spec.rb +6 -0
  30. data/spec/graphql/schema/union_spec.rb +7 -0
  31. data/spec/graphql/upgrader/member_spec.rb +67 -0
  32. data/spec/{graphql → integration/mongoid/graphql}/relay/mongo_relation_connection_spec.rb +0 -11
  33. data/spec/integration/mongoid/spec_helper.rb +2 -0
  34. data/spec/{support → integration/mongoid}/star_trek/data.rb +0 -0
  35. data/spec/{support → integration/mongoid}/star_trek/schema.rb +0 -0
  36. data/spec/{support/star_wars → integration/rails}/data.rb +1 -0
  37. data/spec/{support → integration/rails/generators}/base_generator_test.rb +0 -0
  38. data/spec/{generators → integration/rails/generators}/graphql/enum_generator_spec.rb +0 -0
  39. data/spec/{generators → integration/rails/generators}/graphql/install_generator_spec.rb +0 -0
  40. data/spec/{generators → integration/rails/generators}/graphql/interface_generator_spec.rb +0 -0
  41. data/spec/{generators → integration/rails/generators}/graphql/loader_generator_spec.rb +0 -0
  42. data/spec/{generators → integration/rails/generators}/graphql/mutation_generator_spec.rb +0 -0
  43. data/spec/{generators → integration/rails/generators}/graphql/object_generator_spec.rb +0 -0
  44. data/spec/{generators → integration/rails/generators}/graphql/union_generator_spec.rb +0 -0
  45. data/spec/{graphql → integration/rails/graphql}/input_object_type_spec.rb +0 -0
  46. data/spec/{graphql → integration/rails/graphql}/query/variables_spec.rb +0 -0
  47. data/spec/{graphql → integration/rails/graphql}/relay/array_connection_spec.rb +0 -0
  48. data/spec/{graphql → integration/rails/graphql}/relay/base_connection_spec.rb +0 -0
  49. data/spec/{graphql → integration/rails/graphql}/relay/connection_instrumentation_spec.rb +0 -0
  50. data/spec/{graphql → integration/rails/graphql}/relay/connection_resolve_spec.rb +0 -0
  51. data/spec/{graphql → integration/rails/graphql}/relay/connection_type_spec.rb +0 -0
  52. data/spec/{graphql → integration/rails/graphql}/relay/edge_spec.rb +0 -0
  53. data/spec/{graphql → integration/rails/graphql}/relay/mutation_spec.rb +0 -0
  54. data/spec/{graphql → integration/rails/graphql}/relay/node_spec.rb +0 -0
  55. data/spec/{graphql → integration/rails/graphql}/relay/page_info_spec.rb +0 -0
  56. data/spec/{graphql → integration/rails/graphql}/relay/range_add_spec.rb +0 -0
  57. data/spec/{graphql → integration/rails/graphql}/relay/relation_connection_spec.rb +0 -0
  58. data/spec/{graphql → integration/rails/graphql}/schema_spec.rb +0 -0
  59. data/spec/{graphql → integration/rails/graphql}/tracing/active_support_notifications_tracing_spec.rb +0 -0
  60. data/spec/integration/rails/spec_helper.rb +15 -0
  61. data/spec/spec_helper.rb +16 -39
  62. data/spec/support/jazz.rb +48 -0
  63. metadata +260 -243
  64. data/spec/rails_dependency_sanity_spec.rb +0 -14
@@ -14,6 +14,12 @@ describe GraphQL::Schema::Object do
14
14
  assert object_class.respond_to?(:connection_type)
15
15
  end
16
16
 
17
+ describe "path" do
18
+ it "is the type name" do
19
+ assert_equal "Ensemble", object_class.path
20
+ end
21
+ end
22
+
17
23
  it "inherits fields and interfaces" do
18
24
  new_object_class = Class.new(object_class) do
19
25
  field :newField, String, null: true
@@ -52,6 +52,71 @@ describe GraphQL::Schema::RelayClassicMutation do
52
52
  end
53
53
  end
54
54
 
55
+ describe "loading multiple application objects" do
56
+ let(:query_str) {
57
+ <<-GRAPHQL
58
+ mutation($ids: [ID!]!) {
59
+ upvoteEnsembles(input: {ensembleIds: $ids}) {
60
+ ensembles {
61
+ id
62
+ }
63
+ }
64
+ }
65
+ GRAPHQL
66
+ }
67
+
68
+ it "loads arguments as objects of the given type and strips `_ids` suffix off argument name and appends `s`" do
69
+ res = Jazz::Schema.execute(query_str, variables: { ids: ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"]})
70
+ assert_equal ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"], res["data"]["upvoteEnsembles"]["ensembles"].map { |e| e["id"] }
71
+ end
72
+
73
+ it "uses the `as:` name when loading" do
74
+ as_bands_query_str = query_str.sub("upvoteEnsembles", "upvoteEnsemblesAsBands")
75
+ res = Jazz::Schema.execute(as_bands_query_str, variables: { ids: ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"]})
76
+ assert_equal ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"], res["data"]["upvoteEnsemblesAsBands"]["ensembles"].map { |e| e["id"] }
77
+ end
78
+
79
+ it "doesn't append `s` to argument names that already end in `s`" do
80
+ query = <<-GRAPHQL
81
+ mutation($ids: [ID!]!) {
82
+ upvoteEnsemblesIds(input: {ensemblesIds: $ids}) {
83
+ ensembles {
84
+ id
85
+ }
86
+ }
87
+ }
88
+ GRAPHQL
89
+
90
+ res = Jazz::Schema.execute(query, variables: { ids: ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"]})
91
+ assert_equal ["Ensemble/Robert Glasper Experiment", "Ensemble/Bela Fleck and the Flecktones"], res["data"]["upvoteEnsemblesIds"]["ensembles"].map { |e| e["id"] }
92
+ end
93
+
94
+ it "returns an error instead when the ID resolves to nil" do
95
+ res = Jazz::Schema.execute(query_str, variables: {
96
+ ids: ["Ensemble/Nonexistant Name"],
97
+ })
98
+ assert_nil res["data"].fetch("upvoteEnsembles")
99
+ assert_equal ['No object found for `ensembleIds: "Ensemble/Nonexistant Name"`'], res["errors"].map { |e| e["message"] }
100
+ end
101
+
102
+ it "returns an error instead when the ID resolves to an object of the wrong type" do
103
+ res = Jazz::Schema.execute(query_str, variables: {
104
+ ids: ["Instrument/Organ"],
105
+ })
106
+ assert_nil res["data"].fetch("upvoteEnsembles")
107
+ assert_equal ["No object found for `ensembleIds: \"Instrument/Organ\"`"], res["errors"].map { |e| e["message"] }
108
+ end
109
+
110
+ it "raises an authorization error when the type's auth fails" do
111
+ res = Jazz::Schema.execute(query_str, variables: {
112
+ ids: ["Ensemble/Spinal Tap"],
113
+ })
114
+ assert_nil res["data"].fetch("upvoteEnsembles")
115
+ # Failed silently
116
+ refute res.key?("errors")
117
+ end
118
+ end
119
+
55
120
  describe "loading application objects" do
56
121
  let(:query_str) {
57
122
  <<-GRAPHQL
@@ -70,6 +135,12 @@ describe GraphQL::Schema::RelayClassicMutation do
70
135
  assert_equal "August Greene", res["data"]["renameEnsemble"]["ensemble"]["name"]
71
136
  end
72
137
 
138
+ it "uses the `as:` name when loading" do
139
+ band_query_str = query_str.sub("renameEnsemble", "renameEnsembleAsBand")
140
+ res = Jazz::Schema.execute(band_query_str, variables: { id: "Ensemble/Robert Glasper Experiment", newName: "August Greene"})
141
+ assert_equal "August Greene", res["data"]["renameEnsembleAsBand"]["ensemble"]["name"]
142
+ end
143
+
73
144
  it "returns an error instead when the ID resolves to nil" do
74
145
  res = Jazz::Schema.execute(query_str, variables: {
75
146
  id: "Ensemble/Nonexistant Name",
@@ -192,28 +192,45 @@ describe GraphQL::Schema::Resolver do
192
192
  end
193
193
  end
194
194
 
195
+ class PrepResolver9Array < BaseResolver
196
+ argument :int_ids, [ID], required: true, loads: HasValue, as: :ints
197
+ # Make sure the lazy object is resolved properly:
198
+ type [HasValue], null: false
199
+ def object_from_id(type, id, ctx)
200
+ # Make sure a lazy object is handled appropriately
201
+ LazyBlock.new {
202
+ # Make sure that the right type ends up here
203
+ id.to_i + type.graphql_name.length
204
+ }
205
+ end
206
+
207
+ def resolve(ints:)
208
+ ints.map { |int| int * 3}
209
+ end
210
+ end
211
+
195
212
  class PrepResolver10 < BaseResolver
196
213
  argument :int1, Integer, required: true
197
- argument :int2, Integer, required: true
214
+ argument :int2, Integer, required: true, as: :integer_2
198
215
  type Integer, null: true
199
- def authorized?(int1:, int2:)
200
- if int1 + int2 > context[:max_int]
216
+ def authorized?(int1:, integer_2:)
217
+ if int1 + integer_2 > context[:max_int]
201
218
  raise GraphQL::ExecutionError, "Inputs too big"
202
- elsif context[:min_int] && (int1 + int2 < context[:min_int])
219
+ elsif context[:min_int] && (int1 + integer_2 < context[:min_int])
203
220
  false
204
221
  else
205
222
  true
206
223
  end
207
224
  end
208
225
 
209
- def resolve(int1:, int2:)
210
- int1 + int2
226
+ def resolve(int1:, integer_2:)
227
+ int1 + integer_2
211
228
  end
212
229
  end
213
230
 
214
231
  class PrepResolver11 < PrepResolver10
215
- def authorized?(int1:, int2:)
216
- LazyBlock.new { super(int1: int1 * 2, int2: int2) }
232
+ def authorized?(int1:, integer_2:)
233
+ LazyBlock.new { super(int1: int1 * 2, integer_2: integer_2) }
217
234
  end
218
235
  end
219
236
 
@@ -242,6 +259,17 @@ describe GraphQL::Schema::Resolver do
242
259
  end
243
260
  end
244
261
 
262
+ class PrepResolver14 < GraphQL::Schema::RelayClassicMutation
263
+ field :number, Integer, null: false
264
+
265
+ def authorized?
266
+ true
267
+ end
268
+
269
+ def resolve
270
+ { number: 1 }
271
+ end
272
+ end
245
273
 
246
274
  class Query < GraphQL::Schema::Object
247
275
  class CustomField < GraphQL::Schema::Field
@@ -274,10 +302,12 @@ describe GraphQL::Schema::Resolver do
274
302
  field :prep_resolver_6, resolver: PrepResolver6
275
303
  field :prep_resolver_7, resolver: PrepResolver7
276
304
  field :prep_resolver_9, resolver: PrepResolver9
305
+ field :prep_resolver_9_array, resolver: PrepResolver9Array
277
306
  field :prep_resolver_10, resolver: PrepResolver10
278
307
  field :prep_resolver_11, resolver: PrepResolver11
279
308
  field :prep_resolver_12, resolver: PrepResolver12
280
309
  field :prep_resolver_13, resolver: PrepResolver13
310
+ field :prep_resolver_14, resolver: PrepResolver14
281
311
  end
282
312
 
283
313
  class Schema < GraphQL::Schema
@@ -291,6 +321,22 @@ describe GraphQL::Schema::Resolver do
291
321
  ResolverTest::Schema.execute(*args)
292
322
  end
293
323
 
324
+ describe ".path" do
325
+ it "is the name" do
326
+ assert_equal "Resolver1", ResolverTest::Resolver1.path
327
+ end
328
+
329
+ it "is used for arguments and fields" do
330
+ assert_equal "Resolver1.value", ResolverTest::Resolver1.arguments["value"].path
331
+ assert_equal "PrepResolver7.int", ResolverTest::PrepResolver7.fields["int"].path
332
+ end
333
+
334
+ it "works on instances" do
335
+ r = ResolverTest::Resolver1.new(object: nil, context: nil)
336
+ assert_equal "Resolver1", r.path
337
+ end
338
+ end
339
+
294
340
  it "gets initialized for each resolution" do
295
341
  # State isn't shared between calls:
296
342
  res = exec_query " { r1: resolver1(value: 1) r2: resolver1 }"
@@ -426,6 +472,11 @@ describe GraphQL::Schema::Resolver do
426
472
  assert_equal 11, res["data"]["prepResolver10"]
427
473
  end
428
474
 
475
+ it "uses the argument name provided in `as:`" do
476
+ res = exec_query("{ prepResolver10(int1: 5, int2: 6) }", context: { max_int: 90 })
477
+ assert_equal 11, res["data"]["prepResolver10"]
478
+ end
479
+
429
480
  it "can return a lazy object" do
430
481
  # This is too big because it's modified in the overridden authorized? hook:
431
482
  res = exec_query("{ prepResolver11(int1: 3, int2: 5) }", context: { max_int: 9 })
@@ -462,6 +513,11 @@ describe GraphQL::Schema::Resolver do
462
513
  res = exec_query(str, context: { max_int: 100, min_int: 20 })
463
514
  assert_equal({ "prepResolver10" => nil, "prepResolver11" => nil }, res["data"])
464
515
  end
516
+
517
+ it "works with no arguments for RelayClassicMutation" do
518
+ res = exec_query("{ prepResolver14(input: {}) { number } }")
519
+ assert_equal 1, res["data"]["prepResolver14"]["number"]
520
+ end
465
521
  end
466
522
  end
467
523
 
@@ -471,6 +527,14 @@ describe GraphQL::Schema::Resolver do
471
527
  # (5 + 8) * 3
472
528
  assert_equal 39, res["data"]["prepResolver9"]["value"]
473
529
  end
530
+
531
+ it "supports loading array of ids" do
532
+ res = exec_query('{ prepResolver9Array(intIds: ["1", "10", "100"]) { value } }')
533
+ # (1 + 8) * 3
534
+ # (10 + 8) * 3
535
+ # (100 + 8) * 3
536
+ assert_equal [27, 54, 324], res["data"]["prepResolver9Array"].map { |v| v["value"] }
537
+ end
474
538
  end
475
539
  end
476
540
  end
@@ -2,6 +2,12 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe GraphQL::Schema::Scalar do
5
+ describe ".path" do
6
+ it "is the name" do
7
+ assert_equal "String", GraphQL::Types::String.path
8
+ end
9
+ end
10
+
5
11
  describe "in queries" do
6
12
  it "becomes output" do
7
13
  query_str = <<-GRAPHQL
@@ -3,6 +3,13 @@ require "spec_helper"
3
3
 
4
4
  describe GraphQL::Schema::Union do
5
5
  let(:union) { Jazz::PerformingAct }
6
+
7
+ describe ".path" do
8
+ it "is the name" do
9
+ assert_equal "PerformingAct", union.path
10
+ end
11
+ end
12
+
6
13
  describe "type info" do
7
14
  it "has some" do
8
15
  assert_equal 2, union.possible_types.size
@@ -292,6 +292,10 @@ RUBY
292
292
  new = %{field :name, String, null: false}
293
293
  assert_equal new, upgrade(old)
294
294
 
295
+ old = %{field :name, types.String.to_non_null_type}
296
+ new = %{field :name, String, null: false}
297
+ assert_equal new, upgrade(old)
298
+
295
299
  old = %{field :name, !types.String, "description", method: :name_full}
296
300
  new = %{field :name, String, "description", method: :name_full, null: false}
297
301
  assert_equal new, upgrade(old)
@@ -300,6 +304,10 @@ RUBY
300
304
  new = %{field :name, String, null: false}
301
305
  assert_equal new, upgrade(old)
302
306
 
307
+ old = %{field :name, -> { types.String.to_non_null_type }}
308
+ new = %{field :name, String, null: false}
309
+ assert_equal new, upgrade(old)
310
+
303
311
  old = %{connection :name, Name.connection_type, "names"}
304
312
  new = %{field :name, Name.connection_type, "names", null: true, connection: true}
305
313
  assert_equal new, upgrade(old)
@@ -308,10 +316,18 @@ RUBY
308
316
  new = %{field :name, Name.connection_type, "names", null: false, connection: true}
309
317
  assert_equal new, upgrade(old)
310
318
 
319
+ old = %{connection :name, Name.connection_type.to_non_null_type, "names"}
320
+ new = %{field :name, Name.connection_type, "names", null: false, connection: true}
321
+ assert_equal new, upgrade(old)
322
+
311
323
  old = %{field :names, types[!types.String]}
312
324
  new = %{field :names, [String], null: true}
313
325
  assert_equal new, upgrade(old)
314
326
 
327
+ old = %{field :names, types[types.String.to_non_null_type]}
328
+ new = %{field :names, [String], null: true}
329
+ assert_equal new, upgrade(old)
330
+
315
331
  old = %{field :names, !types[types.String]}
316
332
  new = %{field :names, [String, null: true], null: false}
317
333
  assert_equal new, upgrade(old)
@@ -341,6 +357,22 @@ RUBY
341
357
  }
342
358
  assert_equal new, upgrade(old)
343
359
 
360
+ old = %{
361
+ field :name, types.String.to_non_null_type do
362
+ description "abc"
363
+ end
364
+
365
+ field :name2, types.Int.to_non_null_type do
366
+ description "def"
367
+ end
368
+ }
369
+ new = %{
370
+ field :name, String, description: "abc", null: false
371
+
372
+ field :name2, Integer, description: "def", null: false
373
+ }
374
+ assert_equal new, upgrade(old)
375
+
344
376
  old = %{
345
377
  field :name, -> { !types.String } do
346
378
  end
@@ -350,6 +382,15 @@ RUBY
350
382
  }
351
383
  assert_equal new, upgrade(old)
352
384
 
385
+ old = %{
386
+ field :name, -> { types.String.to_non_null_type } do
387
+ end
388
+ }
389
+ new = %{
390
+ field :name, String, null: false
391
+ }
392
+ assert_equal new, upgrade(old)
393
+
353
394
  old = %{
354
395
  field :name do
355
396
  type -> { String }
@@ -376,6 +417,22 @@ RUBY
376
417
  }
377
418
  assert_equal new, upgrade(old)
378
419
 
420
+ old = %{
421
+ field :name do
422
+ type String.to_non_null_type
423
+ end
424
+
425
+ field :name2 do
426
+ type String.to_non_null_type
427
+ end
428
+ }
429
+ new = %{
430
+ field :name, String, null: false
431
+
432
+ field :name2, String, null: false
433
+ }
434
+ assert_equal new, upgrade(old)
435
+
379
436
  old = %{
380
437
  field :name, -> { types.String },
381
438
  "newline description" do
@@ -396,6 +453,16 @@ RUBY
396
453
  }
397
454
  assert_equal new, upgrade(old)
398
455
 
456
+ old = %{
457
+ field :name, -> { types.String.to_non_null_type },
458
+ "newline description" do
459
+ end
460
+ }
461
+ new = %{
462
+ field :name, String, "newline description", null: false
463
+ }
464
+ assert_equal new, upgrade(old)
465
+
399
466
  old = %{
400
467
  field :name, String,
401
468
  field: SomeField do
@@ -1,18 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'spec_helper'
3
3
 
4
- if MONGO_DETECTED
5
- require "support/star_trek/data"
6
- require "support/star_trek/schema"
7
- end
8
-
9
4
  describe GraphQL::Relay::MongoRelationConnection do
10
- before do
11
- if !MONGO_DETECTED
12
- skip("Mongo not detected")
13
- end
14
- end
15
-
16
5
  def get_names(result)
17
6
  ships = result["data"]["federation"]["bases"]["edges"]
18
7
  ships.map { |e| e["node"]["name"] }
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require "mongoid" if RUBY_ENGINE == 'ruby'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require_relative 'spec_helper'
2
3
  require 'ostruct'
3
4
 
4
5
  # platform helper