graphql 1.8.0.pre1 → 1.8.0.pre2

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/loader_generator.rb +1 -1
  4. data/lib/generators/graphql/mutation_generator.rb +6 -1
  5. data/lib/generators/graphql/templates/function.erb +2 -2
  6. data/lib/generators/graphql/templates/loader.erb +2 -2
  7. data/lib/graphql.rb +1 -0
  8. data/lib/graphql/execution.rb +1 -0
  9. data/lib/graphql/execution/instrumentation.rb +82 -0
  10. data/lib/graphql/execution/multiplex.rb +11 -28
  11. data/lib/graphql/field.rb +5 -0
  12. data/lib/graphql/internal_representation/node.rb +1 -1
  13. data/lib/graphql/language.rb +1 -0
  14. data/lib/graphql/language/document_from_schema_definition.rb +185 -0
  15. data/lib/graphql/language/lexer.rb +3 -3
  16. data/lib/graphql/language/lexer.rl +2 -2
  17. data/lib/graphql/language/token.rb +9 -2
  18. data/lib/graphql/query.rb +4 -0
  19. data/lib/graphql/railtie.rb +83 -0
  20. data/lib/graphql/relay/relation_connection.rb +13 -18
  21. data/lib/graphql/schema.rb +6 -0
  22. data/lib/graphql/schema/argument.rb +1 -1
  23. data/lib/graphql/schema/build_from_definition.rb +2 -0
  24. data/lib/graphql/schema/field.rb +5 -2
  25. data/lib/graphql/schema/input_object.rb +2 -2
  26. data/lib/graphql/schema/member.rb +10 -0
  27. data/lib/graphql/schema/member/build_type.rb +8 -0
  28. data/lib/graphql/schema/member/instrumentation.rb +3 -3
  29. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +6 -4
  30. data/lib/graphql/tracing.rb +1 -0
  31. data/lib/graphql/tracing/data_dog_tracing.rb +45 -0
  32. data/lib/graphql/tracing/platform_tracing.rb +20 -7
  33. data/lib/graphql/upgrader/member.rb +111 -0
  34. data/lib/graphql/upgrader/schema.rb +37 -0
  35. data/lib/graphql/version.rb +1 -1
  36. data/readme.md +1 -1
  37. data/spec/dummy/app/channels/graphql_channel.rb +22 -1
  38. data/spec/dummy/log/development.log +239 -0
  39. data/spec/dummy/log/test.log +204 -0
  40. data/spec/dummy/test/system/action_cable_subscription_test.rb +4 -0
  41. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  42. data/spec/generators/graphql/function_generator_spec.rb +26 -0
  43. data/spec/generators/graphql/loader_generator_spec.rb +24 -0
  44. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  45. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  46. data/spec/graphql/base_type_spec.rb +12 -0
  47. data/spec/graphql/boolean_type_spec.rb +3 -3
  48. data/spec/graphql/execution/execute_spec.rb +1 -1
  49. data/spec/graphql/execution/instrumentation_spec.rb +165 -0
  50. data/spec/graphql/execution/multiplex_spec.rb +1 -1
  51. data/spec/graphql/float_type_spec.rb +2 -2
  52. data/spec/graphql/id_type_spec.rb +1 -1
  53. data/spec/graphql/input_object_type_spec.rb +2 -2
  54. data/spec/graphql/int_type_spec.rb +2 -2
  55. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  56. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  57. data/spec/graphql/language/document_from_schema_definition_spec.rb +337 -0
  58. data/spec/graphql/language/lexer_spec.rb +12 -1
  59. data/spec/graphql/language/parser_spec.rb +1 -1
  60. data/spec/graphql/query/arguments_spec.rb +3 -3
  61. data/spec/graphql/query/variables_spec.rb +1 -1
  62. data/spec/graphql/query_spec.rb +4 -4
  63. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  64. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  65. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  66. data/spec/graphql/relay/mutation_spec.rb +3 -3
  67. data/spec/graphql/relay/relation_connection_spec.rb +58 -0
  68. data/spec/graphql/schema/build_from_definition_spec.rb +14 -0
  69. data/spec/graphql/schema/field_spec.rb +5 -1
  70. data/spec/graphql/schema/instrumentation_spec.rb +39 -0
  71. data/spec/graphql/schema/validation_spec.rb +1 -1
  72. data/spec/graphql/schema/warden_spec.rb +11 -11
  73. data/spec/graphql/schema_spec.rb +8 -1
  74. data/spec/graphql/string_type_spec.rb +3 -3
  75. data/spec/graphql/subscriptions_spec.rb +1 -1
  76. data/spec/graphql/tracing/platform_tracing_spec.rb +59 -0
  77. data/spec/graphql/upgrader/member_spec.rb +222 -0
  78. data/spec/graphql/upgrader/schema_spec.rb +82 -0
  79. data/spec/support/dummy/schema.rb +19 -0
  80. data/spec/support/jazz.rb +14 -14
  81. data/spec/support/star_wars/data.rb +1 -2
  82. metadata +18 -2
@@ -115,8 +115,8 @@ describe GraphQL::Query::Arguments do
115
115
  end
116
116
 
117
117
  it "returns nil for missing keys" do
118
- assert_equal nil, arguments["z"]
119
- assert_equal nil, arguments[7]
118
+ assert_nil arguments["z"]
119
+ assert_nil arguments[7]
120
120
  end
121
121
  end
122
122
 
@@ -303,7 +303,7 @@ describe GraphQL::Query::Arguments do
303
303
  end
304
304
 
305
305
  it "generates argument classes that responds to keys as functions" do
306
- assert_equal nil, input_object.arguments_class
306
+ assert_nil input_object.arguments_class
307
307
 
308
308
  GraphQL::Query::Arguments.construct_arguments_class(input_object)
309
309
  args = input_object.arguments_class.new({foo: 3, bar: -90}, context: nil)
@@ -111,7 +111,7 @@ describe GraphQL::Query::Variables do
111
111
  let(:provided_variables) { { "ids" => [nil] } }
112
112
  it "returns an error" do
113
113
  assert_equal 1, result["errors"].length
114
- assert_equal nil, result["data"]
114
+ assert_nil result["data"]
115
115
  end
116
116
  end
117
117
  end
@@ -111,7 +111,7 @@ describe GraphQL::Query do
111
111
  }
112
112
 
113
113
  it "returns nil" do
114
- assert_equal nil, query.operation_name
114
+ assert_nil query.operation_name
115
115
  end
116
116
  end
117
117
 
@@ -148,7 +148,7 @@ describe GraphQL::Query do
148
148
  }
149
149
 
150
150
  it "returns the inferred operation name" do
151
- assert_equal nil, query.selected_operation_name
151
+ assert_nil query.selected_operation_name
152
152
  end
153
153
  end
154
154
  end
@@ -532,7 +532,7 @@ describe GraphQL::Query do
532
532
 
533
533
  it "overrides the schema's max_depth" do
534
534
  assert result["data"].key?("cheese")
535
- assert_equal nil, result["errors"]
535
+ assert_nil result["errors"]
536
536
  end
537
537
  end
538
538
  end
@@ -699,7 +699,7 @@ describe GraphQL::Query do
699
699
 
700
700
  it "returns nil when there is no selected operation" do
701
701
  query = GraphQL::Query.new(schema, '# Only a comment')
702
- assert_equal nil, query.irep_selection
702
+ assert_nil query.irep_selection
703
703
  end
704
704
  end
705
705
 
@@ -38,7 +38,7 @@ describe GraphQL::Relay::BaseConnection do
38
38
  first: nil,
39
39
  }
40
40
  conn = GraphQL::Relay::BaseConnection.new([], args, context: context)
41
- assert_equal nil, conn.first
41
+ assert_nil conn.first
42
42
  end
43
43
  end
44
44
 
@@ -57,7 +57,7 @@ describe GraphQL::Relay::ConnectionResolve do
57
57
  it "becomes null" do
58
58
  result = star_wars_query(query_string, { "name" => "null" })
59
59
  conn = result["data"]["rebels"]["ships"]
60
- assert_equal nil, conn
60
+ assert_nil conn
61
61
  end
62
62
  end
63
63
  end
@@ -73,7 +73,7 @@ describe GraphQL::Relay::ConnectionType do
73
73
 
74
74
  it "nullifies the parent and adds an error" do
75
75
  result = star_wars_query(query_string)
76
- assert_equal nil, result["data"]["basesWithNullName"]["edges"][0]["node"]
76
+ assert_nil result["data"]["basesWithNullName"]["edges"][0]["node"]
77
77
  assert_equal "Boom!", result["errors"][0]["message"]
78
78
  end
79
79
  end
@@ -193,17 +193,17 @@ describe GraphQL::Relay::Mutation do
193
193
  end
194
194
 
195
195
  it "doesn't get a mutation in the metadata" do
196
- assert_equal nil, custom_return_type.mutation
196
+ assert_nil custom_return_type.mutation
197
197
  end
198
198
 
199
199
  it "supports input fields with nil default value" do
200
200
  assert input.arguments['nullDefault'].default_value?
201
- assert_equal nil, input.arguments['nullDefault'].default_value
201
+ assert_nil input.arguments['nullDefault'].default_value
202
202
  end
203
203
 
204
204
  it "supports input fields with no default value" do
205
205
  assert !input.arguments['noDefault'].default_value?
206
- assert_equal nil, input.arguments['noDefault'].default_value
206
+ assert_nil input.arguments['noDefault'].default_value
207
207
  end
208
208
 
209
209
  it "supports input fields with non-nil default value" do
@@ -74,6 +74,35 @@ describe GraphQL::Relay::RelationConnection do
74
74
  )
75
75
  end
76
76
 
77
+ it "makes one sql query for items and another for count" do
78
+ query_str = <<-GRAPHQL
79
+ {
80
+ empire {
81
+ bases(first: 2) {
82
+ totalCount
83
+ edges {
84
+ cursor
85
+ node {
86
+ name
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ GRAPHQL
93
+ io = StringIO.new
94
+ begin
95
+ prev_logger = ActiveRecord::Base.logger
96
+ ActiveRecord::Base.logger = Logger.new(io)
97
+ result = star_wars_query(query_str, "first" => 2)
98
+ ensure
99
+ ActiveRecord::Base.logger = prev_logger
100
+ end
101
+ assert_equal 2, io.string.scan("\n").count, "Two log entries"
102
+ assert_equal 3, result["data"]["empire"]["bases"]["totalCount"]
103
+ assert_equal 2, result["data"]["empire"]["bases"]["edges"].size
104
+ end
105
+
77
106
  it "provides bidirectional_pagination" do
78
107
  result = star_wars_query(query_string, "first" => 1)
79
108
  last_cursor = get_last_cursor(result)
@@ -564,6 +593,35 @@ describe GraphQL::Relay::RelationConnection do
564
593
  result = star_wars_query(query_string, "last" => 1, "nameIncludes" => "ea", "before" => before)
565
594
  assert_equal(["Death Star"], get_names(result))
566
595
  end
596
+
597
+ it "makes one sql query for items and another for count" do
598
+ query_str = <<-GRAPHQL
599
+ {
600
+ empire {
601
+ basesAsSequelDataset(first: 2) {
602
+ totalCount
603
+ edges {
604
+ cursor
605
+ node {
606
+ name
607
+ }
608
+ }
609
+ }
610
+ }
611
+ }
612
+ GRAPHQL
613
+ result = nil
614
+ io = StringIO.new
615
+ begin
616
+ StarWars::DB.loggers << Logger.new(io)
617
+ result = star_wars_query(query_str, "first" => 2)
618
+ ensure
619
+ StarWars::DB.loggers.pop
620
+ end
621
+ assert_equal 2, io.string.scan("SELECT").count
622
+ assert_equal 3, result["data"]["empire"]["basesAsSequelDataset"]["totalCount"]
623
+ assert_equal 2, result["data"]["empire"]["basesAsSequelDataset"]["edges"].size
624
+ end
567
625
  end
568
626
  end
569
627
 
@@ -30,6 +30,20 @@ type HelloScalars {
30
30
  build_schema_and_compare_output(schema.chop)
31
31
  end
32
32
 
33
+ it 'can build a schema with default input object values' do
34
+ schema = <<-SCHEMA
35
+ input InputObject {
36
+ a: Int
37
+ }
38
+
39
+ type Query {
40
+ a(input: InputObject = {a: 1}): String
41
+ }
42
+ SCHEMA
43
+
44
+ build_schema_and_compare_output(schema.chop)
45
+ end
46
+
33
47
  it 'can build a schema with directives' do
34
48
  schema = <<-SCHEMA
35
49
  schema {
@@ -4,11 +4,15 @@ require "spec_helper"
4
4
  describe GraphQL::Schema::Field do
5
5
  describe "graphql definition" do
6
6
  let(:object_class) { Jazz::Query }
7
- let(:field) { object_class.fields.find { |f| f.name == "find" } }
7
+ let(:field) { object_class.fields.find { |f| f.name == "inspect_input" } }
8
8
 
9
9
  it "uses the argument class" do
10
10
  arg_defn = field.graphql_definition.arguments.values.first
11
11
  assert_equal :ok, arg_defn.metadata[:custom]
12
12
  end
13
+
14
+ it "camelizes the field name" do
15
+ assert_equal 'inspectInput', field.graphql_definition.name
16
+ end
13
17
  end
14
18
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ module InstrumentationSpec
5
+ class SomeInterface < GraphQL::Schema::Interface
6
+ field :neverCalled, String, null: false
7
+
8
+ def never_called
9
+ "should never be called"
10
+ end
11
+ end
12
+
13
+ class SomeType < GraphQL::Schema::Object
14
+ implements SomeInterface
15
+ end
16
+
17
+ class Query < GraphQL::Schema::Object
18
+ field :someField, [SomeInterface], null: true
19
+
20
+ def some_field
21
+ nil
22
+ end
23
+ end
24
+
25
+ class Schema < GraphQL::Schema
26
+ query Query
27
+ orphan_types [SomeType]
28
+ end
29
+ end
30
+
31
+ describe GraphQL::Schema::Member::Instrumentation do
32
+ describe "resolving nullable interface lists to nil" do
33
+ let(:query) { "query { someField { neverCalled } }"}
34
+ it "returns nil instead of failing" do
35
+ result = InstrumentationSpec::Schema.execute(query)
36
+ assert_nil(result["someField"])
37
+ end
38
+ end
39
+ end
@@ -333,7 +333,7 @@ describe GraphQL::Schema::Validation do
333
333
  end
334
334
 
335
335
  it "allows null default value for nullable argument" do
336
- assert_equal nil, GraphQL::Schema::Validation.validate(null_default_value)
336
+ assert_nil GraphQL::Schema::Validation.validate(null_default_value)
337
337
  end
338
338
  end
339
339
 
@@ -242,8 +242,8 @@ describe GraphQL::Schema::Warden do
242
242
  GRAPHQL
243
243
  res = MaskHelpers.query_with_mask(query_string, mask)
244
244
  assert_equal "Query", res["data"]["__schema"]["queryType"]["name"]
245
- assert_equal nil, res["data"]["__schema"]["mutationType"]
246
- assert_equal nil, res["data"]["__schema"]["subscriptionType"]
245
+ assert_nil res["data"]["__schema"]["mutationType"]
246
+ assert_nil res["data"]["__schema"]["subscriptionType"]
247
247
  type_names = res["data"]["__schema"]["types"].map { |t| t["name"] }
248
248
  refute type_names.include?("Mutation")
249
249
  refute type_names.include?("Subscription")
@@ -344,7 +344,7 @@ describe GraphQL::Schema::Warden do
344
344
  res = MaskHelpers.run_query(query_string, only: whitelist)
345
345
 
346
346
  # It's not visible by name
347
- assert_equal nil, res["data"]["Phoneme"]
347
+ assert_nil res["data"]["Phoneme"]
348
348
 
349
349
  # It's not visible in `__schema`
350
350
  all_type_names = type_names(res)
@@ -423,7 +423,7 @@ describe GraphQL::Schema::Warden do
423
423
 
424
424
  res = MaskHelpers.query_with_mask(query_string, mask)
425
425
  type = res["data"]["__type"]
426
- assert_equal nil, type
426
+ assert_nil type
427
427
  end
428
428
  end
429
429
  end
@@ -543,7 +543,7 @@ describe GraphQL::Schema::Warden do
543
543
 
544
544
  res = MaskHelpers.query_with_mask(query_string, mask)
545
545
 
546
- assert_equal nil, res["data"]["WithinInput"], "The type isn't accessible by name"
546
+ assert_nil res["data"]["WithinInput"], "The type isn't accessible by name"
547
547
 
548
548
  languages_arg_names = res["data"]["Query"]["fields"].find { |f| f["name"] == "languages" }["args"].map { |a| a["name"] }
549
549
  refute_includes languages_arg_names, "within", "Arguments that point to it are gone"
@@ -666,7 +666,7 @@ describe GraphQL::Schema::Warden do
666
666
  it "is additive with query filters" do
667
667
  query_except = ->(member, ctx) { member.metadata[:hidden_input_object_type] }
668
668
  res = schema.execute(query_str, except: query_except)
669
- assert_equal nil, res["data"]["input"]
669
+ assert_nil res["data"]["input"]
670
670
  enum_values = res["data"]["enum"]["enumValues"].map { |v| v["name"] }
671
671
  refute_includes enum_values, "TRILL"
672
672
  end
@@ -695,13 +695,13 @@ describe GraphQL::Schema::Warden do
695
695
  only: [visible_enum_value, visible_abstract_type],
696
696
  except: [hidden_input_object, hidden_type],
697
697
  )
698
- assert_equal nil, res["data"]["input"]
698
+ assert_nil res["data"]["input"]
699
699
  enum_values = res["data"]["enum"]["enumValues"].map { |v| v["name"] }
700
700
  assert_equal 5, enum_values.length
701
701
  refute_includes enum_values, "TRILL"
702
702
  # These are also filtered out:
703
703
  assert_equal 0, res["data"]["abstractType"]["interfaces"].length
704
- assert_equal nil, res["data"]["type"]
704
+ assert_nil res["data"]["type"]
705
705
  end
706
706
  end
707
707
 
@@ -712,7 +712,7 @@ describe GraphQL::Schema::Warden do
712
712
  except: hidden_input_object,
713
713
  }
714
714
  res = MaskHelpers.run_query(query_str, context: { filters: filters })
715
- assert_equal nil, res["data"]["input"]
715
+ assert_nil res["data"]["input"]
716
716
  enum_values = res["data"]["enum"]["enumValues"].map { |v| v["name"] }
717
717
  assert_equal 5, enum_values.length
718
718
  refute_includes enum_values, "TRILL"
@@ -727,13 +727,13 @@ describe GraphQL::Schema::Warden do
727
727
  except: [hidden_input_object, hidden_type],
728
728
  }
729
729
  res = MaskHelpers.run_query(query_str, context: { filters: filters })
730
- assert_equal nil, res["data"]["input"]
730
+ assert_nil res["data"]["input"]
731
731
  enum_values = res["data"]["enum"]["enumValues"].map { |v| v["name"] }
732
732
  assert_equal 5, enum_values.length
733
733
  refute_includes enum_values, "TRILL"
734
734
  # These are also filtered out:
735
735
  assert_equal 0, res["data"]["abstractType"]["interfaces"].length
736
- assert_equal nil, res["data"]["type"]
736
+ assert_nil res["data"]["type"]
737
737
  end
738
738
  end
739
739
  end
@@ -23,6 +23,13 @@ describe GraphQL::Schema do
23
23
  end
24
24
  end
25
25
 
26
+ describe "#to_document" do
27
+ it "returns the AST for the schema IDL" do
28
+ expected = GraphQL::Language::DocumentFromSchemaDefinition.new(schema).document
29
+ assert expected.eql?(schema.to_document)
30
+ end
31
+ end
32
+
26
33
  describe "#root_types" do
27
34
  it "returns a list of the schema's root types" do
28
35
  assert_equal(
@@ -372,7 +379,7 @@ type Query {
372
379
  assert_equal true, schema.lazy?(LazyObj.new)
373
380
  assert_equal :dup, schema.lazy_method_name(LazyObjChild.new)
374
381
  assert_equal true, schema.lazy?(LazyObjChild.new)
375
- assert_equal nil, schema.lazy_method_name({})
382
+ assert_nil schema.lazy_method_name({})
376
383
  assert_equal false, schema.lazy?({})
377
384
  end
378
385
  end
@@ -72,9 +72,9 @@ describe GraphQL::STRING_TYPE do
72
72
  end
73
73
 
74
74
  it "doesn't accept other types" do
75
- assert_equal nil, string_type.coerce_isolated_input(100)
76
- assert_equal nil, string_type.coerce_isolated_input(true)
77
- assert_equal nil, string_type.coerce_isolated_input(0.999)
75
+ assert_nil string_type.coerce_isolated_input(100)
76
+ assert_nil string_type.coerce_isolated_input(true)
77
+ assert_nil string_type.coerce_isolated_input(0.999)
78
78
  end
79
79
  end
80
80
  end
@@ -242,7 +242,7 @@ describe GraphQL::Subscriptions do
242
242
  schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "8" }, root_value: root_object)
243
243
  schema.subscriptions.trigger("payload", { "id" => "8"}, OpenStruct.new(str: nil, int: nil))
244
244
  delivery = deliveries["1"].first
245
- assert_equal nil, delivery.fetch("data")
245
+ assert_nil delivery.fetch("data")
246
246
  assert_equal 1, delivery["errors"].length
247
247
  end
248
248
 
@@ -53,4 +53,63 @@ describe GraphQL::Tracing::PlatformTracing do
53
53
  assert_equal expected_trace, CustomPlatformTracer::TRACE
54
54
  end
55
55
  end
56
+
57
+ describe "by default, scalar fields are not traced" do
58
+ let(:schema) {
59
+ Dummy::Schema.redefine {
60
+ use(CustomPlatformTracer)
61
+ }
62
+ }
63
+
64
+ before do
65
+ CustomPlatformTracer::TRACE.clear
66
+ end
67
+
68
+ it "only traces traceTrue, not traceFalse or traceNil" do
69
+ schema.execute(" { tracingScalar { traceNil traceFalse traceTrue } }")
70
+ expected_trace = [
71
+ "em",
72
+ "am",
73
+ "l",
74
+ "p",
75
+ "v",
76
+ "aq",
77
+ "eq",
78
+ "Q.t",
79
+ "T.t",
80
+ "eql",
81
+ ]
82
+ assert_equal expected_trace, CustomPlatformTracer::TRACE
83
+ end
84
+ end
85
+
86
+ describe "when scalar fields are traced by default, they are unless specified" do
87
+ let(:schema) {
88
+ Dummy::Schema.redefine {
89
+ use(CustomPlatformTracer, trace_scalars: true)
90
+ }
91
+ }
92
+
93
+ before do
94
+ CustomPlatformTracer::TRACE.clear
95
+ end
96
+
97
+ it "traces traceTrue and traceNil but not traceFalse" do
98
+ schema.execute(" { tracingScalar { traceNil traceFalse traceTrue } }")
99
+ expected_trace = [
100
+ "em",
101
+ "am",
102
+ "l",
103
+ "p",
104
+ "v",
105
+ "aq",
106
+ "eq",
107
+ "Q.t",
108
+ "T.t",
109
+ "T.t",
110
+ "eql",
111
+ ]
112
+ assert_equal expected_trace, CustomPlatformTracer::TRACE
113
+ end
114
+ end
56
115
  end