graphql 1.9.7 → 1.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +2 -1
  3. data/lib/generators/graphql/templates/base_argument.erb +4 -0
  4. data/lib/generators/graphql/templates/base_field.erb +2 -0
  5. data/lib/generators/graphql/templates/base_input_object.erb +1 -0
  6. data/lib/graphql/analysis/ast/query_complexity.rb +34 -18
  7. data/lib/graphql/argument.rb +8 -2
  8. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +1 -1
  9. data/lib/graphql/language/lexer.rb +24 -13
  10. data/lib/graphql/language/lexer.rl +23 -13
  11. data/lib/graphql/query/arguments.rb +16 -15
  12. data/lib/graphql/schema.rb +105 -48
  13. data/lib/graphql/schema/argument.rb +12 -1
  14. data/lib/graphql/schema/build_from_definition.rb +3 -0
  15. data/lib/graphql/schema/field.rb +3 -8
  16. data/lib/graphql/schema/find_inherited_value.rb +20 -0
  17. data/lib/graphql/schema/input_object.rb +1 -3
  18. data/lib/graphql/schema/loader.rb +1 -0
  19. data/lib/graphql/schema/member/base_dsl_methods.rb +7 -18
  20. data/lib/graphql/schema/member/has_arguments.rb +4 -9
  21. data/lib/graphql/schema/member/has_fields.rb +14 -0
  22. data/lib/graphql/schema/member/relay_shortcuts.rb +2 -2
  23. data/lib/graphql/schema/resolver.rb +31 -8
  24. data/lib/graphql/schema/resolver/has_payload_type.rb +3 -2
  25. data/lib/graphql/schema/subscription.rb +1 -1
  26. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  27. data/lib/graphql/version.rb +1 -1
  28. data/spec/graphql/analysis/analyze_query_spec.rb +14 -25
  29. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +7 -19
  30. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +5 -12
  31. data/spec/graphql/analysis/max_query_complexity_spec.rb +12 -20
  32. data/spec/graphql/analysis/max_query_depth_spec.rb +6 -13
  33. data/spec/graphql/language/lexer_spec.rb +19 -1
  34. data/spec/graphql/schema/argument_spec.rb +1 -1
  35. data/spec/graphql/schema/build_from_definition_spec.rb +10 -0
  36. data/spec/graphql/schema/catchall_middleware_spec.rb +6 -9
  37. data/spec/graphql/schema/input_object_spec.rb +25 -0
  38. data/spec/graphql/schema/loader_spec.rb +65 -1
  39. data/spec/graphql/schema/object_spec.rb +21 -0
  40. data/spec/graphql/schema/resolver_spec.rb +30 -1
  41. data/spec/graphql/schema_spec.rb +135 -0
  42. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +25 -0
  43. data/spec/integration/rails/generators/graphql/install_generator_spec.rb +20 -0
  44. data/spec/integration/tmp/app/graphql/types/page_type.rb +5 -0
  45. data/spec/support/dummy/schema.rb +1 -1
  46. data/spec/support/lazy_helpers.rb +1 -1
  47. data/spec/support/parser/filename_example_invalid_utf8.graphql +1 -0
  48. metadata +10 -132
  49. data/spec/integration/tmp/app/graphql/types/date_type.rb +0 -14
  50. data/spec/integration/tmp/dummy/Gemfile +0 -50
  51. data/spec/integration/tmp/dummy/README.md +0 -24
  52. data/spec/integration/tmp/dummy/Rakefile +0 -6
  53. data/spec/integration/tmp/dummy/app/assets/config/manifest.js +0 -3
  54. data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +0 -16
  55. data/spec/integration/tmp/dummy/app/assets/javascripts/cable.js +0 -13
  56. data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +0 -15
  57. data/spec/integration/tmp/dummy/app/channels/application_cable/channel.rb +0 -5
  58. data/spec/integration/tmp/dummy/app/channels/application_cable/connection.rb +0 -5
  59. data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +0 -4
  60. data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +0 -44
  61. data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +0 -3
  62. data/spec/integration/tmp/dummy/app/jobs/application_job.rb +0 -3
  63. data/spec/integration/tmp/dummy/app/mailers/application_mailer.rb +0 -5
  64. data/spec/integration/tmp/dummy/app/mydirectory/dummy_schema.rb +0 -5
  65. data/spec/integration/tmp/dummy/app/mydirectory/mutations/update_name.rb +0 -15
  66. data/spec/integration/tmp/dummy/app/mydirectory/types/base_enum.rb +0 -5
  67. data/spec/integration/tmp/dummy/app/mydirectory/types/base_input_object.rb +0 -5
  68. data/spec/integration/tmp/dummy/app/mydirectory/types/base_interface.rb +0 -6
  69. data/spec/integration/tmp/dummy/app/mydirectory/types/base_object.rb +0 -5
  70. data/spec/integration/tmp/dummy/app/mydirectory/types/base_scalar.rb +0 -5
  71. data/spec/integration/tmp/dummy/app/mydirectory/types/base_union.rb +0 -5
  72. data/spec/integration/tmp/dummy/app/mydirectory/types/mutation_type.rb +0 -12
  73. data/spec/integration/tmp/dummy/app/mydirectory/types/query_type.rb +0 -14
  74. data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +0 -14
  75. data/spec/integration/tmp/dummy/app/views/layouts/mailer.html.erb +0 -13
  76. data/spec/integration/tmp/dummy/app/views/layouts/mailer.text.erb +0 -1
  77. data/spec/integration/tmp/dummy/bin/bundle +0 -3
  78. data/spec/integration/tmp/dummy/bin/rails +0 -4
  79. data/spec/integration/tmp/dummy/bin/rake +0 -4
  80. data/spec/integration/tmp/dummy/bin/setup +0 -34
  81. data/spec/integration/tmp/dummy/bin/update +0 -29
  82. data/spec/integration/tmp/dummy/config.ru +0 -5
  83. data/spec/integration/tmp/dummy/config/application.rb +0 -26
  84. data/spec/integration/tmp/dummy/config/boot.rb +0 -4
  85. data/spec/integration/tmp/dummy/config/cable.yml +0 -9
  86. data/spec/integration/tmp/dummy/config/environment.rb +0 -6
  87. data/spec/integration/tmp/dummy/config/environments/development.rb +0 -52
  88. data/spec/integration/tmp/dummy/config/environments/production.rb +0 -84
  89. data/spec/integration/tmp/dummy/config/environments/test.rb +0 -43
  90. data/spec/integration/tmp/dummy/config/initializers/application_controller_renderer.rb +0 -9
  91. data/spec/integration/tmp/dummy/config/initializers/assets.rb +0 -12
  92. data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +0 -8
  93. data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +0 -6
  94. data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +0 -5
  95. data/spec/integration/tmp/dummy/config/initializers/inflections.rb +0 -17
  96. data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +0 -5
  97. data/spec/integration/tmp/dummy/config/initializers/new_framework_defaults.rb +0 -24
  98. data/spec/integration/tmp/dummy/config/initializers/session_store.rb +0 -4
  99. data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +0 -10
  100. data/spec/integration/tmp/dummy/config/locales/en.yml +0 -23
  101. data/spec/integration/tmp/dummy/config/puma.rb +0 -48
  102. data/spec/integration/tmp/dummy/config/routes.rb +0 -9
  103. data/spec/integration/tmp/dummy/config/secrets.yml +0 -22
  104. data/spec/integration/tmp/dummy/db/seeds.rb +0 -8
  105. data/spec/integration/tmp/dummy/log/test.log +0 -0
  106. data/spec/integration/tmp/dummy/public/404.html +0 -67
  107. data/spec/integration/tmp/dummy/public/422.html +0 -67
  108. data/spec/integration/tmp/dummy/public/500.html +0 -66
  109. data/spec/integration/tmp/dummy/public/apple-touch-icon-precomposed.png +0 -0
  110. data/spec/integration/tmp/dummy/public/apple-touch-icon.png +0 -0
  111. data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
  112. data/spec/integration/tmp/dummy/public/robots.txt +0 -5
  113. data/spec/integration/tmp/dummy/test/test_helper.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc1010a9a70360cc6b3d6dcb13db9d35c207179686f503d01d5904c2655f9ae2
4
- data.tar.gz: 510f939a5c9dd9b1a66610e7d526aa84e9ae2b494f76a9a07973aef0b24e6cde
3
+ metadata.gz: 8b6424d74c67296edb56f74eb9214313dd9556f1c1ba5e5797c58099afea8958
4
+ data.tar.gz: ae10d626a73f8dc873f2b9b2678bfc3ffc1cd80301ddd15a255e4447c728d285
5
5
  SHA512:
6
- metadata.gz: bebd9ccec78e0ba8e2d2a13d351a33e9a169261faf954bc50710f80c4ad6d555e495761681e0691213a9ed409b3057f77118f91e73e577fdd988759e4c7eb743
7
- data.tar.gz: d458a432047fa847b775f8ff5558084eb2cc845a5277d4f47643483de5f9049d2b19c8c7831058c79b28bc962000d8f13c5201a7396169fa81bf080be8f12e18
6
+ metadata.gz: 51b253d7218b850a4189affeee6e298d1367e8781289ca2f828ab6bbd70d6a1de205f29531ff697d70807d8107f62c3b9cbfc6325f7847116836ab4f500206ce
7
+ data.tar.gz: f9a81a828f9835ce1222021d0ae3f251c576eba5845df2034e8330456765d2920a28850fa24b7f58cbc7d3e1442bd405995cc3a4bf8d7e17277a73ba8fdb8ab6
@@ -13,6 +13,7 @@ module Graphql
13
13
  # - graphql/
14
14
  # - resolvers/
15
15
  # - types/
16
+ # - base_argument.rb
16
17
  # - base_field.rb
17
18
  # - base_enum.rb
18
19
  # - base_input_object.rb
@@ -94,7 +95,7 @@ module Graphql
94
95
  create_dir("#{options[:directory]}/types")
95
96
  template("schema.erb", schema_file_path)
96
97
 
97
- ["base_object", "base_field", "base_enum", "base_input_object", "base_interface", "base_scalar", "base_union"].each do |base_type|
98
+ ["base_object", "base_argument", "base_field", "base_enum", "base_input_object", "base_interface", "base_scalar", "base_union"].each do |base_type|
98
99
  template("#{base_type}.erb", "#{options[:directory]}/types/#{base_type}.rb")
99
100
  end
100
101
 
@@ -0,0 +1,4 @@
1
+ module Types
2
+ class BaseArgument < GraphQL::Schema::Argument
3
+ end
4
+ end
@@ -1,5 +1,7 @@
1
1
  module Types
2
2
  class BaseField < GraphQL::Schema::Field
3
+ argument_class Types::BaseArgument
4
+
3
5
  def resolve_field(obj, args, ctx)
4
6
  resolve(obj, args, ctx)
5
7
  end
@@ -1,4 +1,5 @@
1
1
  module Types
2
2
  class BaseInputObject < GraphQL::Schema::InputObject
3
+ argument_class Types::BaseArgument
3
4
  end
4
5
  end
@@ -4,11 +4,11 @@ module GraphQL
4
4
  # Calculate the complexity of a query, using {Field#complexity} values.
5
5
  module AST
6
6
  class QueryComplexity < Analyzer
7
- # State for the query complexity calcuation:
7
+ # State for the query complexity calculation:
8
8
  # - `complexities_on_type` holds complexity scores for each type in an IRep node
9
9
  def initialize(query)
10
10
  super
11
- @complexities_on_type = [TypeComplexity.new]
11
+ @complexities_on_type = [ConcreteTypeComplexity.new]
12
12
  end
13
13
 
14
14
  # Overide this method to use the complexity result
@@ -22,7 +22,11 @@ module GraphQL
22
22
  return if visitor.visiting_fragment_definition?
23
23
  return if visitor.skipping?
24
24
 
25
- @complexities_on_type.push(TypeComplexity.new)
25
+ if visitor.type_definition.kind.abstract?
26
+ @complexities_on_type.push(AbstractTypeComplexity.new)
27
+ else
28
+ @complexities_on_type.push(ConcreteTypeComplexity.new)
29
+ end
26
30
  end
27
31
 
28
32
  def on_leave_field(node, parent, visitor)
@@ -35,17 +39,14 @@ module GraphQL
35
39
  child_complexity = type_complexities.max_possible_complexity
36
40
  own_complexity = get_complexity(node, visitor.field_definition, child_complexity, visitor)
37
41
 
38
- parent_type = visitor.parent_type_definition
39
- possible_types = if parent_type.kind.abstract?
40
- query.possible_types(parent_type)
42
+ if @complexities_on_type.last.is_a?(AbstractTypeComplexity)
43
+ key = selection_key(visitor.response_path, visitor.query)
44
+ parent_type = visitor.parent_type_definition
45
+ query.possible_types(parent_type).each do |type|
46
+ @complexities_on_type.last.merge(type, key, own_complexity)
47
+ end
41
48
  else
42
- [parent_type]
43
- end
44
-
45
- key = selection_key(visitor.response_path, visitor.query)
46
-
47
- possible_types.each do |type|
48
- @complexities_on_type.last.merge(type, key, own_complexity)
49
+ @complexities_on_type.last.merge(own_complexity)
49
50
  end
50
51
  end
51
52
 
@@ -68,7 +69,7 @@ module GraphQL
68
69
  # We add the query object id to support multiplex queries
69
70
  # even if they have the same response path, they should
70
71
  # always be added.
71
- response_path.join(".") + "-#{query.object_id}"
72
+ "#{response_path.join(".")}-#{query.object_id}"
72
73
  end
73
74
 
74
75
  # Get a complexity value for a field,
@@ -91,16 +92,19 @@ module GraphQL
91
92
 
92
93
  # Selections on an object may apply differently depending on what is _actually_ returned by the resolve function.
93
94
  # Find the maximum possible complexity among those combinations.
94
- class TypeComplexity
95
+ class AbstractTypeComplexity
95
96
  def initialize
96
97
  @types = Hash.new { |h, k| h[k] = {} }
97
98
  end
98
99
 
99
100
  # Return the max possible complexity for types in this selection
100
101
  def max_possible_complexity
101
- @types.map do |type, fields|
102
- fields.values.inject(:+)
103
- end.max
102
+ max = 0
103
+ @types.each_value do |fields|
104
+ complexity = fields.each_value.inject(:+)
105
+ max = complexity if complexity > max
106
+ end
107
+ max
104
108
  end
105
109
 
106
110
  # Store the complexity for the branch on `type_defn`.
@@ -109,6 +113,18 @@ module GraphQL
109
113
  @types[type_defn][key] = complexity
110
114
  end
111
115
  end
116
+
117
+ class ConcreteTypeComplexity
118
+ attr_reader :max_possible_complexity
119
+
120
+ def initialize
121
+ @max_possible_complexity = 0
122
+ end
123
+
124
+ def merge(complexity)
125
+ @max_possible_complexity += complexity
126
+ end
127
+ end
112
128
  end
113
129
  end
114
130
  end
@@ -35,13 +35,14 @@ module GraphQL
35
35
 
36
36
  class Argument
37
37
  include GraphQL::Define::InstanceDefinable
38
- accepts_definitions :name, :type, :description, :default_value, :as, :prepare
38
+ accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access
39
39
  attr_reader :default_value
40
40
  attr_accessor :description, :name, :as
41
41
  attr_accessor :ast_node
42
+ attr_accessor :method_access
42
43
  alias :graphql_name :name
43
44
 
44
- ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare)
45
+ ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access)
45
46
 
46
47
  # @api private
47
48
  module DefaultPrepare
@@ -60,6 +61,11 @@ module GraphQL
60
61
  !!@has_default_value
61
62
  end
62
63
 
64
+ def method_access?
65
+ # Treat unset as true -- only `false` should override
66
+ @method_access != false
67
+ end
68
+
63
69
  def default_value=(new_default_value)
64
70
  if new_default_value == NO_DEFAULT_VALUE
65
71
  @has_default_value = false
@@ -88,7 +88,7 @@ module GraphQL
88
88
  end
89
89
 
90
90
  connection :pushes, lazy_push_type.connection_type do
91
- argument :values, types[types.Int]
91
+ argument :values, types[types.Int], method_access: false
92
92
  resolve ->(o, a, c) {
93
93
  LazyPushCollection.new(c, a[:values])
94
94
  }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GraphQL
2
4
  module Language
3
5
  module Lexer
@@ -1369,7 +1371,7 @@ end
1369
1371
  def self.record_comment(ts, te, meta)
1370
1372
  token = GraphQL::Language::Token.new(
1371
1373
  name: :COMMENT,
1372
- value: meta[:data][ts...te].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1374
+ value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1373
1375
  line: meta[:line],
1374
1376
  col: meta[:col],
1375
1377
  prev_token: meta[:previous_token],
@@ -1383,7 +1385,7 @@ end
1383
1385
  def self.emit(token_name, ts, te, meta)
1384
1386
  meta[:tokens] << token = GraphQL::Language::Token.new(
1385
1387
  name: token_name,
1386
- value: meta[:data][ts...te].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1388
+ value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1387
1389
  line: meta[:line],
1388
1390
  col: meta[:col],
1389
1391
  prev_token: meta[:previous_token],
@@ -1415,16 +1417,15 @@ UTF_8_ENCODING = "UTF-8"
1415
1417
 
1416
1418
  def self.emit_string(ts, te, meta, block:)
1417
1419
  quotes_length = block ? 3 : 1
1418
- ts += quotes_length
1419
- value = meta[:data][ts...te - quotes_length].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING)
1420
+ value = meta[:data][ts + quotes_length, te - ts - 2 * quotes_length].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING) || ''
1420
1421
  line_incr = 0
1421
- if block
1422
+ if block && !value.length.zero?
1422
1423
  line_incr = value.count("\n")
1423
1424
  value = GraphQL::Language::BlockString.trim_whitespace(value)
1424
1425
  end
1425
1426
  # TODO: replace with `String#match?` when we support only Ruby 2.4+
1426
1427
  # (It's faster: https://bugs.ruby-lang.org/issues/8110)
1427
- if value !~ VALID_STRING
1428
+ if !value.valid_encoding? || value !~ VALID_STRING
1428
1429
  meta[:tokens] << token = GraphQL::Language::Token.new(
1429
1430
  name: :BAD_UNICODE_ESCAPE,
1430
1431
  value: value,
@@ -1435,13 +1436,23 @@ prev_token: meta[:previous_token],
1435
1436
  else
1436
1437
  replace_escaped_characters_in_place(value)
1437
1438
 
1438
- meta[:tokens] << token = GraphQL::Language::Token.new(
1439
- name: :STRING,
1440
- value: value,
1441
- line: meta[:line],
1442
- col: meta[:col],
1443
- prev_token: meta[:previous_token],
1444
- )
1439
+ if !value.valid_encoding?
1440
+ meta[:tokens] << token = GraphQL::Language::Token.new(
1441
+ name: :BAD_UNICODE_ESCAPE,
1442
+ value: value,
1443
+ line: meta[:line],
1444
+ col: meta[:col],
1445
+ prev_token: meta[:previous_token],
1446
+ )
1447
+ else
1448
+ meta[:tokens] << token = GraphQL::Language::Token.new(
1449
+ name: :STRING,
1450
+ value: value,
1451
+ line: meta[:line],
1452
+ col: meta[:col],
1453
+ prev_token: meta[:previous_token],
1454
+ )
1455
+ end
1445
1456
  end
1446
1457
 
1447
1458
  meta[:previous_token] = token
@@ -105,6 +105,7 @@
105
105
  *|;
106
106
  }%%
107
107
 
108
+ # frozen_string_literal: true
108
109
 
109
110
  module GraphQL
110
111
  module Language
@@ -152,7 +153,7 @@ module GraphQL
152
153
  def self.record_comment(ts, te, meta)
153
154
  token = GraphQL::Language::Token.new(
154
155
  name: :COMMENT,
155
- value: meta[:data][ts...te].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
156
+ value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
156
157
  line: meta[:line],
157
158
  col: meta[:col],
158
159
  prev_token: meta[:previous_token],
@@ -166,7 +167,7 @@ module GraphQL
166
167
  def self.emit(token_name, ts, te, meta)
167
168
  meta[:tokens] << token = GraphQL::Language::Token.new(
168
169
  name: token_name,
169
- value: meta[:data][ts...te].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
170
+ value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
170
171
  line: meta[:line],
171
172
  col: meta[:col],
172
173
  prev_token: meta[:previous_token],
@@ -198,16 +199,15 @@ module GraphQL
198
199
 
199
200
  def self.emit_string(ts, te, meta, block:)
200
201
  quotes_length = block ? 3 : 1
201
- ts += quotes_length
202
- value = meta[:data][ts...te - quotes_length].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING)
202
+ value = meta[:data][ts + quotes_length, te - ts - 2 * quotes_length].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING) || ''
203
203
  line_incr = 0
204
- if block
204
+ if block && !value.length.zero?
205
205
  line_incr = value.count("\n")
206
206
  value = GraphQL::Language::BlockString.trim_whitespace(value)
207
207
  end
208
208
  # TODO: replace with `String#match?` when we support only Ruby 2.4+
209
209
  # (It's faster: https://bugs.ruby-lang.org/issues/8110)
210
- if value !~ VALID_STRING
210
+ if !value.valid_encoding? || value !~ VALID_STRING
211
211
  meta[:tokens] << token = GraphQL::Language::Token.new(
212
212
  name: :BAD_UNICODE_ESCAPE,
213
213
  value: value,
@@ -218,13 +218,23 @@ module GraphQL
218
218
  else
219
219
  replace_escaped_characters_in_place(value)
220
220
 
221
- meta[:tokens] << token = GraphQL::Language::Token.new(
222
- name: :STRING,
223
- value: value,
224
- line: meta[:line],
225
- col: meta[:col],
226
- prev_token: meta[:previous_token],
227
- )
221
+ if !value.valid_encoding?
222
+ meta[:tokens] << token = GraphQL::Language::Token.new(
223
+ name: :BAD_UNICODE_ESCAPE,
224
+ value: value,
225
+ line: meta[:line],
226
+ col: meta[:col],
227
+ prev_token: meta[:previous_token],
228
+ )
229
+ else
230
+ meta[:tokens] << token = GraphQL::Language::Token.new(
231
+ name: :STRING,
232
+ value: value,
233
+ line: meta[:line],
234
+ col: meta[:col],
235
+ prev_token: meta[:previous_token],
236
+ )
237
+ end
228
238
  end
229
239
 
230
240
  meta[:previous_token] = token
@@ -14,21 +14,22 @@ module GraphQL
14
14
  self.argument_definitions = argument_definitions
15
15
 
16
16
  argument_definitions.each do |_arg_name, arg_definition|
17
- expose_as = arg_definition.expose_as.to_s.freeze
18
- expose_as_underscored = GraphQL::Schema::Member::BuildType.underscore(expose_as).freeze
19
- method_names = [expose_as, expose_as_underscored].uniq
20
- method_names.each do |method_name|
21
- # Don't define a helper method if it would override something.
22
- if method_defined?(method_name)
23
- warn(
24
- "Unable to define a helper for argument with name '#{method_name}' "\
25
- "as this is a reserved name. If you're using an argument such as "\
26
- "`argument #{method_name}`, consider renaming this argument.`"
27
- )
28
- else
29
- define_method(method_name) do
30
- # Always use `expose_as` here, since #[] doesn't accept underscored names
31
- self[expose_as]
17
+ if arg_definition.method_access?
18
+ expose_as = arg_definition.expose_as.to_s.freeze
19
+ expose_as_underscored = GraphQL::Schema::Member::BuildType.underscore(expose_as).freeze
20
+ method_names = [expose_as, expose_as_underscored].uniq
21
+ method_names.each do |method_name|
22
+ # Don't define a helper method if it would override something.
23
+ if method_defined?(method_name)
24
+ warn(
25
+ "Unable to define a helper for argument with name '#{method_name}' "\
26
+ "as this is a reserved name. Add `method_access: false` to stop this warning."
27
+ )
28
+ else
29
+ define_method(method_name) do
30
+ # Always use `expose_as` here, since #[] doesn't accept underscored names
31
+ self[expose_as]
32
+ end
32
33
  end
33
34
  end
34
35
  end
@@ -3,6 +3,7 @@ require "graphql/schema/base_64_encoder"
3
3
  require "graphql/schema/catchall_middleware"
4
4
  require "graphql/schema/default_parse_error"
5
5
  require "graphql/schema/default_type_error"
6
+ require "graphql/schema/find_inherited_value"
6
7
  require "graphql/schema/finder"
7
8
  require "graphql/schema/invalid_type_error"
8
9
  require "graphql/schema/introspection_system"
@@ -81,6 +82,8 @@ module GraphQL
81
82
  extend Forwardable
82
83
  extend GraphQL::Schema::Member::AcceptsDefinition
83
84
  include GraphQL::Define::InstanceDefinable
85
+ extend GraphQL::Schema::FindInheritedValue
86
+
84
87
  accepts_definitions \
85
88
  :query, :mutation, :subscription,
86
89
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
@@ -159,7 +162,9 @@ module GraphQL
159
162
  # @see {Query#tracers} for query-specific tracers
160
163
  attr_reader :tracers
161
164
 
162
- DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
165
+ DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
166
+ EMPTY_ARRAY = [].freeze
167
+ EMPTY_HASH = {}.freeze
163
168
 
164
169
  attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
165
170
 
@@ -728,11 +733,11 @@ module GraphQL
728
733
  end
729
734
 
730
735
  def use(plugin, options = {})
731
- plugins << [plugin, options]
736
+ own_plugins << [plugin, options]
732
737
  end
733
738
 
734
739
  def plugins
735
- @plugins ||= []
740
+ find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
736
741
  end
737
742
 
738
743
  def to_graphql
@@ -746,7 +751,7 @@ module GraphQL
746
751
  schema_defn.max_depth = max_depth
747
752
  schema_defn.default_max_page_size = default_max_page_size
748
753
  schema_defn.orphan_types = orphan_types
749
- schema_defn.disable_introspection_entry_points = @disable_introspection_entry_points
754
+ schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
750
755
 
751
756
  prepped_dirs = {}
752
757
  directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
@@ -758,15 +763,15 @@ module GraphQL
758
763
  schema_defn.type_error = method(:type_error)
759
764
  schema_defn.context_class = context_class
760
765
  schema_defn.cursor_encoder = cursor_encoder
761
- schema_defn.tracers.concat(defined_tracers)
762
- schema_defn.query_analyzers.concat(defined_query_analyzers)
766
+ schema_defn.tracers.concat(tracers)
767
+ schema_defn.query_analyzers.concat(query_analyzers)
763
768
 
764
- schema_defn.middleware.concat(defined_middleware)
765
- schema_defn.multiplex_analyzers.concat(defined_multiplex_analyzers)
769
+ schema_defn.middleware.concat(all_middleware)
770
+ schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
766
771
  schema_defn.query_execution_strategy = query_execution_strategy
767
772
  schema_defn.mutation_execution_strategy = mutation_execution_strategy
768
773
  schema_defn.subscription_execution_strategy = subscription_execution_strategy
769
- defined_instrumenters.each do |step, insts|
774
+ all_instrumenters.each do |step, insts|
770
775
  insts.each do |inst|
771
776
  schema_defn.instrumenters[step] << inst
772
777
  end
@@ -774,10 +779,8 @@ module GraphQL
774
779
  lazy_classes.each do |lazy_class, value_method|
775
780
  schema_defn.lazy_methods.set(lazy_class, value_method)
776
781
  end
777
- if @rescues
778
- @rescues.each do |err_class, handler|
779
- schema_defn.rescue_from(err_class, &handler)
780
- end
782
+ rescues.each do |err_class, handler|
783
+ schema_defn.rescue_from(err_class, &handler)
781
784
  end
782
785
 
783
786
  if plugins.any?
@@ -806,7 +809,8 @@ module GraphQL
806
809
  if new_query_object
807
810
  @query_object = new_query_object
808
811
  else
809
- @query_object.respond_to?(:graphql_definition) ? @query_object.graphql_definition : @query_object
812
+ query_object = @query_object || find_inherited_value(:query)
813
+ query_object.respond_to?(:graphql_definition) ? query_object.graphql_definition : query_object
810
814
  end
811
815
  end
812
816
 
@@ -814,7 +818,8 @@ module GraphQL
814
818
  if new_mutation_object
815
819
  @mutation_object = new_mutation_object
816
820
  else
817
- @mutation_object.respond_to?(:graphql_definition) ? @mutation_object.graphql_definition : @mutation_object
821
+ mutation_object = @mutation_object || find_inherited_value(:mutation)
822
+ mutation_object.respond_to?(:graphql_definition) ? mutation_object.graphql_definition : mutation_object
818
823
  end
819
824
  end
820
825
 
@@ -822,7 +827,8 @@ module GraphQL
822
827
  if new_subscription_object
823
828
  @subscription_object = new_subscription_object
824
829
  else
825
- @subscription_object.respond_to?(:graphql_definition) ? @subscription_object.graphql_definition : @subscription_object
830
+ subscription_object = @subscription_object || find_inherited_value(:subscription)
831
+ subscription_object.respond_to?(:graphql_definition) ? subscription_object.graphql_definition : subscription_object
826
832
  end
827
833
  end
828
834
 
@@ -830,7 +836,7 @@ module GraphQL
830
836
  if new_introspection_namespace
831
837
  @introspection = new_introspection_namespace
832
838
  else
833
- @introspection
839
+ @introspection || find_inherited_value(:introspection)
834
840
  end
835
841
  end
836
842
 
@@ -838,14 +844,14 @@ module GraphQL
838
844
  if new_encoder
839
845
  @cursor_encoder = new_encoder
840
846
  end
841
- @cursor_encoder || Base64Encoder
847
+ @cursor_encoder || find_inherited_value(:cursor_encoder, Base64Encoder)
842
848
  end
843
849
 
844
850
  def default_max_page_size(new_default_max_page_size = nil)
845
851
  if new_default_max_page_size
846
852
  @default_max_page_size = new_default_max_page_size
847
853
  else
848
- @default_max_page_size
854
+ @default_max_page_size || find_inherited_value(:default_max_page_size)
849
855
  end
850
856
  end
851
857
 
@@ -853,7 +859,7 @@ module GraphQL
853
859
  if new_query_execution_strategy
854
860
  @query_execution_strategy = new_query_execution_strategy
855
861
  else
856
- @query_execution_strategy || self.default_execution_strategy
862
+ @query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
857
863
  end
858
864
  end
859
865
 
@@ -861,7 +867,7 @@ module GraphQL
861
867
  if new_mutation_execution_strategy
862
868
  @mutation_execution_strategy = new_mutation_execution_strategy
863
869
  else
864
- @mutation_execution_strategy || self.default_execution_strategy
870
+ @mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
865
871
  end
866
872
  end
867
873
 
@@ -869,7 +875,7 @@ module GraphQL
869
875
  if new_subscription_execution_strategy
870
876
  @subscription_execution_strategy = new_subscription_execution_strategy
871
877
  else
872
- @subscription_execution_strategy || self.default_execution_strategy
878
+ @subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
873
879
  end
874
880
  end
875
881
 
@@ -877,7 +883,7 @@ module GraphQL
877
883
  if max_complexity
878
884
  @max_complexity = max_complexity
879
885
  else
880
- @max_complexity
886
+ @max_complexity || find_inherited_value(:max_complexity)
881
887
  end
882
888
  end
883
889
 
@@ -885,7 +891,7 @@ module GraphQL
885
891
  if !new_error_bubbling.nil?
886
892
  @error_bubbling = new_error_bubbling
887
893
  else
888
- @error_bubbling
894
+ @error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
889
895
  end
890
896
  end
891
897
 
@@ -893,7 +899,7 @@ module GraphQL
893
899
  if new_max_depth
894
900
  @max_depth = new_max_depth
895
901
  else
896
- @max_depth
902
+ @max_depth || find_inherited_value(:max_depth)
897
903
  end
898
904
  end
899
905
 
@@ -901,12 +907,20 @@ module GraphQL
901
907
  @disable_introspection_entry_points = true
902
908
  end
903
909
 
910
+ def disable_introspection_entry_points?
911
+ if instance_variable_defined?(:@disable_introspection_entry_points)
912
+ @disable_introspection_entry_points
913
+ else
914
+ find_inherited_value(:disable_introspection_entry_points?, false)
915
+ end
916
+ end
917
+
904
918
  def orphan_types(*new_orphan_types)
905
919
  if new_orphan_types.any?
906
- @orphan_types = new_orphan_types.flatten
907
- else
908
- @orphan_types || []
920
+ own_orphan_types.concat(new_orphan_types.flatten)
909
921
  end
922
+
923
+ find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
910
924
  end
911
925
 
912
926
  def default_execution_strategy
@@ -921,17 +935,20 @@ module GraphQL
921
935
  if new_context_class
922
936
  @context_class = new_context_class
923
937
  else
924
- @context_class || GraphQL::Query::Context
938
+ @context_class || find_inherited_value(:context_class, GraphQL::Query::Context)
925
939
  end
926
940
  end
927
941
 
928
942
  def rescue_from(*err_classes, &handler_block)
929
- @rescues ||= {}
930
943
  err_classes.each do |err_class|
931
- @rescues[err_class] = handler_block
944
+ own_rescues[err_class] = handler_block
932
945
  end
933
946
  end
934
947
 
948
+ def rescues
949
+ find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
950
+ end
951
+
935
952
  def resolve_type(type, obj, ctx)
936
953
  if type.kind.object?
937
954
  type
@@ -1017,19 +1034,20 @@ module GraphQL
1017
1034
  else
1018
1035
  instrument_step
1019
1036
  end
1020
- defined_instrumenters[step] << instrumenter
1037
+
1038
+ own_instrumenters[step] << instrumenter
1021
1039
  end
1022
1040
 
1023
1041
  def directives(new_directives = nil)
1024
1042
  if new_directives
1025
- @directives = new_directives.reduce({}) { |m, d| m[d.name] = d; m }
1043
+ new_directives.each {|d| directive(d) }
1026
1044
  end
1027
1045
 
1028
- @directives ||= default_directives
1046
+ find_inherited_value(:directives, default_directives).merge(own_directives)
1029
1047
  end
1030
1048
 
1031
1049
  def directive(new_directive)
1032
- directives[new_directive.graphql_name] = new_directive
1050
+ own_directives[new_directive.graphql_name] = new_directive
1033
1051
  end
1034
1052
 
1035
1053
  def default_directives
@@ -1041,26 +1059,38 @@ module GraphQL
1041
1059
  end
1042
1060
 
1043
1061
  def tracer(new_tracer)
1044
- defined_tracers << new_tracer
1062
+ own_tracers << new_tracer
1063
+ end
1064
+
1065
+ def tracers
1066
+ find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1045
1067
  end
1046
1068
 
1047
1069
  def query_analyzer(new_analyzer)
1048
1070
  if new_analyzer == GraphQL::Authorization::Analyzer
1049
1071
  warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1050
1072
  end
1051
- defined_query_analyzers << new_analyzer
1073
+ own_query_analyzers << new_analyzer
1074
+ end
1075
+
1076
+ def query_analyzers
1077
+ find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1052
1078
  end
1053
1079
 
1054
1080
  def middleware(new_middleware = nil)
1055
1081
  if new_middleware
1056
- defined_middleware << new_middleware
1082
+ own_middleware << new_middleware
1057
1083
  else
1058
1084
  graphql_definition.middleware
1059
1085
  end
1060
1086
  end
1061
1087
 
1062
1088
  def multiplex_analyzer(new_analyzer)
1063
- defined_multiplex_analyzers << new_analyzer
1089
+ own_multiplex_analyzers << new_analyzer
1090
+ end
1091
+
1092
+ def multiplex_analyzers
1093
+ find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1064
1094
  end
1065
1095
 
1066
1096
  private
@@ -1069,24 +1099,51 @@ module GraphQL
1069
1099
  @lazy_classes ||= {}
1070
1100
  end
1071
1101
 
1072
- def defined_instrumenters
1073
- @defined_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1102
+ def own_plugins
1103
+ @own_plugins ||= []
1104
+ end
1105
+
1106
+ def own_rescues
1107
+ @own_rescues ||= {}
1074
1108
  end
1075
1109
 
1076
- def defined_tracers
1077
- @defined_tracers ||= []
1110
+ def own_orphan_types
1111
+ @own_orphan_types ||= []
1078
1112
  end
1079
1113
 
1080
- def defined_query_analyzers
1114
+ def own_directives
1115
+ @own_directives ||= {}
1116
+ end
1117
+
1118
+ def all_instrumenters
1119
+ inherited_instrumenters = find_inherited_value(:all_instrumenters) || Hash.new { |h,k| h[k] = [] }
1120
+ inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
1121
+ inherited + own
1122
+ end
1123
+ end
1124
+
1125
+ def own_instrumenters
1126
+ @own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1127
+ end
1128
+
1129
+ def own_tracers
1130
+ @own_tracers ||= []
1131
+ end
1132
+
1133
+ def own_query_analyzers
1081
1134
  @defined_query_analyzers ||= []
1082
1135
  end
1083
1136
 
1084
- def defined_middleware
1085
- @defined_middleware ||= []
1137
+ def all_middleware
1138
+ find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1139
+ end
1140
+
1141
+ def own_middleware
1142
+ @own_middleware ||= []
1086
1143
  end
1087
1144
 
1088
- def defined_multiplex_analyzers
1089
- @defined_multiplex_analyzers ||= []
1145
+ def own_multiplex_analyzers
1146
+ @own_multiplex_analyzers ||= []
1090
1147
  end
1091
1148
 
1092
1149
  # Given this schema member, find the class-based definition object