graphql 1.13.0 → 1.13.4

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

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