graphql 1.13.0 → 1.13.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -1
  3. data/lib/generators/graphql/install_generator.rb +9 -2
  4. data/lib/graphql/analysis/ast/field_usage.rb +6 -2
  5. data/lib/graphql/base_type.rb +4 -2
  6. data/lib/graphql/boolean_type.rb +1 -1
  7. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  8. data/lib/graphql/directive/include_directive.rb +1 -1
  9. data/lib/graphql/directive/skip_directive.rb +1 -1
  10. data/lib/graphql/execution/interpreter/runtime.rb +11 -7
  11. data/lib/graphql/execution/multiplex.rb +3 -0
  12. data/lib/graphql/float_type.rb +1 -1
  13. data/lib/graphql/id_type.rb +1 -1
  14. data/lib/graphql/int_type.rb +1 -1
  15. data/lib/graphql/language/block_string.rb +2 -2
  16. data/lib/graphql/language/document_from_schema_definition.rb +7 -3
  17. data/lib/graphql/language/nodes.rb +11 -2
  18. data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
  19. data/lib/graphql/pagination/relation_connection.rb +57 -27
  20. data/lib/graphql/query/context.rb +10 -0
  21. data/lib/graphql/relay/global_id_resolve.rb +1 -1
  22. data/lib/graphql/relay/page_info.rb +1 -1
  23. data/lib/graphql/schema/argument.rb +8 -10
  24. data/lib/graphql/schema/directive.rb +5 -1
  25. data/lib/graphql/schema/enum.rb +3 -1
  26. data/lib/graphql/schema/enum_value.rb +2 -0
  27. data/lib/graphql/schema/field.rb +139 -62
  28. data/lib/graphql/schema/field_extension.rb +89 -2
  29. data/lib/graphql/schema/input_object.rb +18 -1
  30. data/lib/graphql/schema/interface.rb +3 -1
  31. data/lib/graphql/schema/introspection_system.rb +1 -1
  32. data/lib/graphql/schema/list.rb +3 -1
  33. data/lib/graphql/schema/member/accepts_definition.rb +7 -2
  34. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  35. data/lib/graphql/schema/non_null.rb +7 -1
  36. data/lib/graphql/schema/object.rb +3 -1
  37. data/lib/graphql/schema/relay_classic_mutation.rb +8 -0
  38. data/lib/graphql/schema/resolver.rb +19 -13
  39. data/lib/graphql/schema/scalar.rb +2 -0
  40. data/lib/graphql/schema/traversal.rb +1 -1
  41. data/lib/graphql/schema/union.rb +2 -0
  42. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  43. data/lib/graphql/schema/validator.rb +4 -7
  44. data/lib/graphql/schema.rb +24 -8
  45. data/lib/graphql/static_validation/all_rules.rb +1 -0
  46. data/lib/graphql/static_validation/rules/fields_will_merge.rb +14 -7
  47. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  48. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  49. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -0
  50. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +6 -0
  51. data/lib/graphql/string_type.rb +1 -1
  52. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -0
  53. data/lib/graphql/subscriptions/serialize.rb +22 -2
  54. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  55. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  56. data/lib/graphql/types/relay/connection_behaviors.rb +26 -9
  57. data/lib/graphql/types/relay/default_relay.rb +5 -1
  58. data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
  59. data/lib/graphql/types/relay/node_field.rb +14 -3
  60. data/lib/graphql/types/relay/nodes_field.rb +13 -3
  61. data/lib/graphql/version.rb +1 -1
  62. data/lib/graphql.rb +1 -1
  63. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 853fa0482ef0c3bafe04dce77dff9bb685633a1e4c273fd234169f98d595352c
4
- data.tar.gz: 6cf800af8dfc469f4d7a375ee22f6d98e03207799f813f10176916f09a0a4064
3
+ metadata.gz: 51f1e91399e97a5376028af68f7f9c0f01b2d7ff8f342ada08eb984302ea56c3
4
+ data.tar.gz: eb2a62700254c18263f19ae05027f64b725df4bbb100e2c251652a16cfab6afb
5
5
  SHA512:
6
- metadata.gz: 7bcd2b94fa64ab65fb47995a4896b08629bfc9b66f7797dfd4959ad8ccdb5332bf63ae49f5139c7d1766b3d72cb500da257c611e628dc5db36ae26b472c5d51c
7
- data.tar.gz: 51a5c6791429c17940d8d0a5407efb852fd4ddbe7a5eaf706dd8fb074a6654f17b32b08f21956e4e450dff6cff05fb0020a7ff8a141fe38f3e09b8433ca1b4ea
6
+ metadata.gz: 861c8880bf96831e4072f51bcb8dc5e6302040b88ffd7d94cea2288ef281bd317a2235fe98b10ca10687c2f616ac6a740729149ecd44ab4cef2779a9838e7c42
7
+ data.tar.gz: 985e2119a77f367503b133ce37108a7bedaf99c21c6edb6f6eb1b25d2be80954233f9344afb52f19ffbfca864844b180f11b07b09baf58462066b4c1794c830e
@@ -19,7 +19,9 @@ module Graphql
19
19
  sentinel = /< GraphQL::Schema\s*\n/m
20
20
 
21
21
  in_root do
22
- inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
22
+ if File.exist?(schema_file_path)
23
+ inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
24
+ end
23
25
  end
24
26
  end
25
27
 
@@ -122,8 +122,15 @@ module Graphql
122
122
  if options.api?
123
123
  say("Skipped graphiql, as this rails project is API only")
124
124
  say(" You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app")
125
- elsif !options[:skip_graphiql] && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
126
- gem("graphiql-rails", group: :development)
125
+ elsif !options[:skip_graphiql]
126
+ # `gem(...)` uses `gsub_file(...)` under the hood, which is a no-op for `rails destroy...` (when `behavior == :revoke`).
127
+ # So handle that case by calling `gsub_file` with `force: true`.
128
+ if behavior == :invoke && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
129
+ gem("graphiql-rails", group: :development)
130
+ elsif behavior == :revoke
131
+ gemfile_pattern = /\n\s*gem ('|")graphiql-rails('|"), :?group(:| =>) :development/
132
+ gsub_file Rails.root.join("Gemfile"), gemfile_pattern, "", { force: true }
133
+ end
127
134
 
128
135
  # This is a little cheat just to get cleaner shell output:
129
136
  log :route, 'graphiql-rails'
@@ -15,8 +15,12 @@ module GraphQL
15
15
  field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
16
16
  @used_fields << field
17
17
  @used_deprecated_fields << field if field_defn.deprecation_reason
18
-
19
- extract_deprecated_arguments(visitor.query.arguments_for(node, visitor.field_definition).argument_values)
18
+ arguments = visitor.query.arguments_for(node, visitor.field_definition)
19
+ # If there was an error when preparing this argument object,
20
+ # then this might be an error or something:
21
+ if arguments.respond_to?(:argument_values)
22
+ extract_deprecated_arguments(arguments.argument_values)
23
+ end
20
24
  end
21
25
 
22
26
  def result
@@ -41,7 +41,9 @@ module GraphQL
41
41
  alias :graphql_name :name
42
42
  # Future-compatible alias
43
43
  # @see {GraphQL::SchemaMember}
44
- alias :graphql_definition :itself
44
+ def graphql_definition(silence_deprecation_warning: false)
45
+ itself
46
+ end
45
47
 
46
48
  def type_class
47
49
  metadata[:type_class]
@@ -194,7 +196,7 @@ module GraphQL
194
196
  resolve_related_type(Object.const_get(type_arg))
195
197
  else
196
198
  if type_arg.respond_to?(:graphql_definition)
197
- type_arg.graphql_definition
199
+ type_arg.graphql_definition(silence_deprecation_warning: true)
198
200
  else
199
201
  type_arg
200
202
  end
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::BOOLEAN_TYPE = GraphQL::Types::Boolean.graphql_definition
2
+ GraphQL::BOOLEAN_TYPE = GraphQL::Types::Boolean.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::DeprecatedDirective = GraphQL::Schema::Directive::Deprecated.graphql_definition
2
+ GraphQL::Directive::DeprecatedDirective = GraphQL::Schema::Directive::Deprecated.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition
2
+ GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition
2
+ GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition(silence_deprecation_warning: true)
@@ -516,7 +516,7 @@ module GraphQL
516
516
  after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
517
517
  continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
518
518
  if HALT != continue_value
519
- continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments, result_name, selection_result)
519
+ continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
520
520
  end
521
521
  end
522
522
  end
@@ -870,16 +870,20 @@ module GraphQL
870
870
  # but don't wrap the continuation below
871
871
  inner_obj = begin
872
872
  query.with_error_handling do
873
- if trace
874
- query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
873
+ begin
874
+ if trace
875
+ query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
876
+ schema.sync_lazy(lazy_obj)
877
+ end
878
+ else
875
879
  schema.sync_lazy(lazy_obj)
876
880
  end
877
- else
878
- schema.sync_lazy(lazy_obj)
881
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
882
+ err
879
883
  end
880
884
  end
881
- rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
882
- err
885
+ rescue GraphQL::ExecutionError => ex_err
886
+ ex_err
883
887
  end
884
888
  yield(inner_obj)
885
889
  end
@@ -151,6 +151,9 @@ module GraphQL
151
151
 
152
152
  result
153
153
  end
154
+ if query.context.namespace?(:__query_result_extensions__)
155
+ query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
156
+ end
154
157
  end
155
158
 
156
159
  # use the old `query_execution_strategy` etc to run this query
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition
2
+ GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition
2
+ GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition
2
+ GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition(silence_deprecation_warning: true)
@@ -7,7 +7,7 @@ module GraphQL
7
7
  def self.trim_whitespace(str)
8
8
  # Early return for the most common cases:
9
9
  if str == ""
10
- return ""
10
+ return "".dup
11
11
  elsif !(has_newline = str.include?("\n")) && !(str.start_with?(" "))
12
12
  return str
13
13
  end
@@ -55,7 +55,7 @@ module GraphQL
55
55
  end
56
56
 
57
57
  # Rebuild the string
58
- lines.size > 1 ? lines.join("\n") : (lines.first || "")
58
+ lines.size > 1 ? lines.join("\n") : (lines.first || "".dup)
59
59
  end
60
60
 
61
61
  def self.print(str, indent: '')
@@ -196,10 +196,14 @@ module GraphQL
196
196
  when "INPUT_OBJECT"
197
197
  GraphQL::Language::Nodes::InputObject.new(
198
198
  arguments: default_value.to_h.map do |arg_name, arg_value|
199
- arg_type = @warden.arguments(type).find { |a| a.graphql_name == arg_name.to_s }.type
199
+ args = @warden.arguments(type)
200
+ arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
201
+ if arg.nil?
202
+ raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
203
+ end
200
204
  GraphQL::Language::Nodes::Argument.new(
201
- name: arg_name.to_s,
202
- value: build_default_value(arg_value, arg_type)
205
+ name: arg.graphql_name.to_s,
206
+ value: build_default_value(arg_value, arg.type)
203
207
  )
204
208
  end
205
209
  )
@@ -197,7 +197,16 @@ module GraphQL
197
197
  else
198
198
  module_eval <<-RUBY, __FILE__, __LINE__
199
199
  def children
200
- @children ||= (#{children_of_type.keys.map { |k| "@#{k}" }.join(" + ")}).freeze
200
+ @children ||= begin
201
+ if #{children_of_type.keys.map { |k| "@#{k}.any?" }.join(" || ")}
202
+ new_children = []
203
+ #{children_of_type.keys.map { |k| "new_children.concat(@#{k})" }.join("; ")}
204
+ new_children.freeze
205
+ new_children
206
+ else
207
+ NO_CHILDREN
208
+ end
209
+ end
201
210
  end
202
211
  RUBY
203
212
  end
@@ -332,7 +341,7 @@ module GraphQL
332
341
  # end
333
342
  # end
334
343
  #
335
- # document.to_query_string(printer: VariableSrubber.new)
344
+ # document.to_query_string(printer: VariableScrubber.new)
336
345
  #
337
346
  class Document < AbstractNode
338
347
  scalar_methods false
@@ -7,13 +7,18 @@ module GraphQL
7
7
  class ActiveRecordRelationConnection < Pagination::RelationConnection
8
8
  private
9
9
 
10
- def relation_larger_than(relation, size)
11
- initial_offset = relation.offset_value || 0
12
- relation.offset(initial_offset + size).exists?
10
+ def relation_larger_than(relation, initial_offset, size)
11
+ if already_loaded?(relation)
12
+ (relation.size + initial_offset) > size
13
+ else
14
+ set_offset(sliced_nodes, initial_offset + size).exists?
15
+ end
13
16
  end
14
17
 
15
18
  def relation_count(relation)
16
- int_or_hash = if relation.respond_to?(:unscope)
19
+ int_or_hash = if already_loaded?(relation)
20
+ relation.size
21
+ elsif relation.respond_to?(:unscope)
17
22
  relation.unscope(:order).count(:all)
18
23
  else
19
24
  # Rails 3
@@ -28,11 +33,19 @@ module GraphQL
28
33
  end
29
34
 
30
35
  def relation_limit(relation)
31
- relation.limit_value
36
+ if relation.is_a?(Array)
37
+ nil
38
+ else
39
+ relation.limit_value
40
+ end
32
41
  end
33
42
 
34
43
  def relation_offset(relation)
35
- relation.offset_value
44
+ if relation.is_a?(Array)
45
+ nil
46
+ else
47
+ relation.offset_value
48
+ end
36
49
  end
37
50
 
38
51
  def null_relation(relation)
@@ -43,6 +56,30 @@ module GraphQL
43
56
  relation.where("1=2")
44
57
  end
45
58
  end
59
+
60
+ def set_limit(nodes, limit)
61
+ if already_loaded?(nodes)
62
+ nodes.take(limit)
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def set_offset(nodes, offset)
69
+ if already_loaded?(nodes)
70
+ # If the client sent a bogus cursor beyond the size of the relation,
71
+ # it might get `nil` from `#[...]`, so return an empty array in that case
72
+ nodes[offset..-1] || []
73
+ else
74
+ super
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def already_loaded?(relation)
81
+ relation.is_a?(Array) || relation.loaded?
82
+ end
46
83
  end
47
84
  end
48
85
  end
@@ -35,7 +35,7 @@ module GraphQL
35
35
  if @nodes && @nodes.count < first
36
36
  false
37
37
  else
38
- relation_larger_than(sliced_nodes, first)
38
+ relation_larger_than(sliced_nodes, @sliced_nodes_offset, first)
39
39
  end
40
40
  else
41
41
  false
@@ -54,9 +54,10 @@ module GraphQL
54
54
  private
55
55
 
56
56
  # @param relation [Object] A database query object
57
+ # @param _initial_offset [Integer] The number of items already excluded from the relation
57
58
  # @param size [Integer] The value against which we check the relation size
58
59
  # @return [Boolean] True if the number of items in this relation is larger than `size`
59
- def relation_larger_than(relation, size)
60
+ def relation_larger_than(relation, _initial_offset, size)
60
61
  relation_count(set_limit(relation, size + 1)) == size + 1
61
62
  end
62
63
 
@@ -111,30 +112,51 @@ module GraphQL
111
112
  end
112
113
  end
113
114
 
114
- # Apply `before` and `after` to the underlying `items`,
115
- # returning a new relation.
116
- def sliced_nodes
117
- @sliced_nodes ||= begin
118
- paginated_nodes = items
119
-
115
+ def calculate_sliced_nodes_parameters
116
+ if defined?(@sliced_nodes_limit)
117
+ return
118
+ else
120
119
  if after_offset
121
120
  previous_offset = relation_offset(items) || 0
122
- paginated_nodes = set_offset(paginated_nodes, previous_offset + after_offset)
121
+ relation_offset = previous_offset + after_offset
123
122
  end
124
123
 
125
124
  if before_offset && after_offset
126
125
  if after_offset < before_offset
127
126
  # Get the number of items between the two cursors
128
127
  space_between = before_offset - after_offset - 1
129
- paginated_nodes = set_limit(paginated_nodes, space_between)
128
+ relation_limit = space_between
130
129
  else
131
- # TODO I think this is untested
132
130
  # The cursors overextend one another to an empty set
133
- paginated_nodes = null_relation(paginated_nodes)
131
+ @sliced_nodes_null_relation = true
134
132
  end
135
133
  elsif before_offset
136
134
  # Use limit to cut off the tail of the relation
137
- paginated_nodes = set_limit(paginated_nodes, before_offset - 1)
135
+ relation_limit = before_offset - 1
136
+ end
137
+
138
+ @sliced_nodes_limit = relation_limit
139
+ @sliced_nodes_offset = relation_offset || 0
140
+ end
141
+ end
142
+
143
+ # Apply `before` and `after` to the underlying `items`,
144
+ # returning a new relation.
145
+ def sliced_nodes
146
+ @sliced_nodes ||= begin
147
+ calculate_sliced_nodes_parameters
148
+ paginated_nodes = items
149
+
150
+ if @sliced_nodes_null_relation
151
+ paginated_nodes = null_relation(paginated_nodes)
152
+ else
153
+ if @sliced_nodes_limit
154
+ paginated_nodes = set_limit(paginated_nodes, @sliced_nodes_limit)
155
+ end
156
+
157
+ if @sliced_nodes_offset
158
+ paginated_nodes = set_offset(paginated_nodes, @sliced_nodes_offset)
159
+ end
138
160
  end
139
161
 
140
162
  paginated_nodes
@@ -155,32 +177,40 @@ module GraphQL
155
177
  # returning a new relation
156
178
  def limited_nodes
157
179
  @limited_nodes ||= begin
158
- paginated_nodes = sliced_nodes
159
- previous_limit = relation_limit(paginated_nodes)
180
+ calculate_sliced_nodes_parameters
181
+ if @sliced_nodes_null_relation
182
+ # it's an empty set
183
+ return sliced_nodes
184
+ end
185
+ relation_limit = @sliced_nodes_limit
186
+ relation_offset = @sliced_nodes_offset
160
187
 
161
- if first && (previous_limit.nil? || previous_limit > first)
188
+ if first && (relation_limit.nil? || relation_limit > first)
162
189
  # `first` would create a stricter limit that the one already applied, so add it
163
- paginated_nodes = set_limit(paginated_nodes, first)
190
+ relation_limit = first
164
191
  end
165
192
 
166
193
  if last
167
- if (lv = relation_limit(paginated_nodes))
168
- if last <= lv
194
+ if relation_limit
195
+ if last <= relation_limit
169
196
  # `last` is a smaller slice than the current limit, so apply it
170
- offset = (relation_offset(paginated_nodes) || 0) + (lv - last)
171
- paginated_nodes = set_offset(paginated_nodes, offset)
172
- paginated_nodes = set_limit(paginated_nodes, last)
197
+ relation_offset += (relation_limit - last)
198
+ relation_limit = last
173
199
  end
174
200
  else
175
201
  # No limit, so get the last items
176
- sliced_nodes_count = relation_count(@sliced_nodes)
177
- offset = (relation_offset(paginated_nodes) || 0) + sliced_nodes_count - [last, sliced_nodes_count].min
178
- paginated_nodes = set_offset(paginated_nodes, offset)
179
- paginated_nodes = set_limit(paginated_nodes, last)
202
+ sliced_nodes_count = relation_count(sliced_nodes)
203
+ relation_offset += (sliced_nodes_count - [last, sliced_nodes_count].min)
204
+ relation_limit = last
180
205
  end
181
206
  end
182
207
 
183
- @paged_nodes_offset = relation_offset(paginated_nodes)
208
+ @paged_nodes_offset = relation_offset
209
+ paginated_nodes = items
210
+ paginated_nodes = set_offset(paginated_nodes, relation_offset)
211
+ if relation_limit
212
+ paginated_nodes = set_limit(paginated_nodes, relation_limit)
213
+ end
184
214
  paginated_nodes
185
215
  end
186
216
  end
@@ -156,6 +156,11 @@ module GraphQL
156
156
  @scoped_context = {}
157
157
  end
158
158
 
159
+ # @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
160
+ def response_extensions
161
+ namespace(:__query_result_extensions__)
162
+ end
163
+
159
164
  def dataloader
160
165
  @dataloader ||= self[:dataloader] || (query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new)
161
166
  end
@@ -236,6 +241,11 @@ module GraphQL
236
241
  @storage[ns]
237
242
  end
238
243
 
244
+ # @return [Boolean] true if this namespace was accessed before
245
+ def namespace?(ns)
246
+ @storage.key?(ns)
247
+ end
248
+
239
249
  def inspect
240
250
  "#<Query::Context ...>"
241
251
  end
@@ -10,7 +10,7 @@ module GraphQL
10
10
  if obj.is_a?(GraphQL::Schema::Object)
11
11
  obj = obj.object
12
12
  end
13
- type = @type.respond_to?(:graphql_definition) ? @type.graphql_definition : @type
13
+ type = @type.respond_to?(:graphql_definition) ? @type.graphql_definition(silence_deprecation_warning: true) : @type
14
14
  ctx.query.schema.id_from_object(obj, type, ctx)
15
15
  end
16
16
  end
@@ -2,6 +2,6 @@
2
2
  module GraphQL
3
3
  module Relay
4
4
  # Wrap a Connection and expose its page info
5
- PageInfo = GraphQL::Types::Relay::PageInfo.graphql_definition
5
+ PageInfo = GraphQL::Types::Relay::PageInfo.graphql_definition(silence_deprecation_warning: true)
6
6
  end
7
7
  end
@@ -37,7 +37,7 @@ module GraphQL
37
37
  # @param arg_name [Symbol]
38
38
  # @param type_expr
39
39
  # @param desc [String]
40
- # @param required [Boolean] if true, this argument is non-null; if false, this argument is nullable
40
+ # @param required [Boolean, :nullable] if true, this argument is non-null; if false, this argument is nullable. If `:nullable`, then the argument must be provided, though it may be `null`.
41
41
  # @param description [String]
42
42
  # @param default_value [Object]
43
43
  # @param as [Symbol] Override the keyword name when passed to a method
@@ -53,7 +53,7 @@ module GraphQL
53
53
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
54
54
  @type_expr = type_expr || type
55
55
  @description = desc || description
56
- @null = !required
56
+ @null = required != true
57
57
  @default_value = default_value
58
58
  @owner = owner
59
59
  @as = as
@@ -72,6 +72,9 @@ module GraphQL
72
72
  end
73
73
 
74
74
  self.validates(validates)
75
+ if required == :nullable
76
+ self.owner.validates(required: { argument: arg_name })
77
+ end
75
78
 
76
79
  if definition_block
77
80
  if definition_block.arity == 1
@@ -147,20 +150,15 @@ module GraphQL
147
150
  end
148
151
  end
149
152
  elsif as_type.kind.input_object?
150
- as_type.arguments(ctx).each do |_name, input_obj_arg|
151
- input_obj_arg = input_obj_arg.type_class
152
- # TODO: this skips input objects whose values were alread replaced with application objects.
153
- # See: https://github.com/rmosolgo/graphql-ruby/issues/2633
154
- if value.is_a?(InputObject) && value.key?(input_obj_arg.keyword) && !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
155
- return false
156
- end
157
- end
153
+ return as_type.authorized?(obj, value, ctx)
158
154
  end
159
155
  # None of the early-return conditions were activated,
160
156
  # so this is authorized.
161
157
  true
162
158
  end
163
159
 
160
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
161
+
164
162
  def to_graphql
165
163
  argument = GraphQL::Argument.new
166
164
  argument.name = @name
@@ -8,6 +8,8 @@ module GraphQL
8
8
  # - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
+ extend GraphQL::Schema::Member::AcceptsDefinition
12
+
11
13
  class << self
12
14
  # Directives aren't types, they don't have kinds.
13
15
  undef_method :kind
@@ -53,6 +55,8 @@ module GraphQL
53
55
  default_directive
54
56
  end
55
57
 
58
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
59
+
56
60
  def to_graphql
57
61
  defn = GraphQL::Directive.new
58
62
  defn.name = self.graphql_name
@@ -62,7 +66,7 @@ module GraphQL
62
66
  defn.ast_node = ast_node
63
67
  defn.metadata[:type_class] = self
64
68
  all_argument_definitions.each do |arg_defn|
65
- arg_graphql = arg_defn.to_graphql
69
+ arg_graphql = arg_defn.to_graphql(silence_deprecation_warning: true)
66
70
  defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
67
71
  end
68
72
  # Make a reference to a classic-style Arguments class
@@ -108,6 +108,8 @@ module GraphQL
108
108
  enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
109
109
  end
110
110
 
111
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
112
+
111
113
  # @return [GraphQL::EnumType]
112
114
  def to_graphql
113
115
  enum_type = GraphQL::EnumType.new
@@ -116,7 +118,7 @@ module GraphQL
116
118
  enum_type.introspection = introspection
117
119
  enum_type.ast_node = ast_node
118
120
  values.each do |name, val|
119
- enum_type.add_value(val.to_graphql)
121
+ enum_type.add_value(val.deprecated_to_graphql)
120
122
  end
121
123
  enum_type.metadata[:type_class] = self
122
124
  enum_type
@@ -73,6 +73,8 @@ module GraphQL
73
73
  @value
74
74
  end
75
75
 
76
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
77
+
76
78
  # @return [GraphQL::EnumType::EnumValue] A runtime-ready object derived from this object
77
79
  def to_graphql
78
80
  enum_value = GraphQL::EnumType::EnumValue.new