graphql 1.9.7 → 1.9.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 (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