graphql 2.2.17 → 2.5.16

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 (240) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install_generator.rb +46 -0
  4. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  5. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  6. data/lib/generators/graphql/templates/schema.erb +3 -0
  7. data/lib/generators/graphql/type_generator.rb +1 -1
  8. data/lib/graphql/analysis/analyzer.rb +90 -0
  9. data/lib/graphql/analysis/field_usage.rb +82 -0
  10. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  11. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  12. data/lib/graphql/analysis/query_complexity.rb +263 -0
  13. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  14. data/lib/graphql/analysis/visitor.rb +280 -0
  15. data/lib/graphql/analysis.rb +95 -1
  16. data/lib/graphql/autoload.rb +38 -0
  17. data/lib/graphql/backtrace/table.rb +118 -55
  18. data/lib/graphql/backtrace.rb +1 -19
  19. data/lib/graphql/current.rb +57 -0
  20. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  21. data/lib/graphql/dashboard/installable.rb +22 -0
  22. data/lib/graphql/dashboard/limiters.rb +93 -0
  23. data/lib/graphql/dashboard/operation_store.rb +199 -0
  24. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  25. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  26. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  27. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  28. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  29. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  30. data/lib/graphql/dashboard/statics/icon.png +0 -0
  31. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  36. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  37. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  38. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  39. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  40. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  41. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  42. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  43. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  44. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  45. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  46. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  47. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  48. data/lib/graphql/dashboard.rb +158 -0
  49. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  50. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  51. data/lib/graphql/dataloader/async_dataloader.rb +46 -19
  52. data/lib/graphql/dataloader/null_dataloader.rb +51 -10
  53. data/lib/graphql/dataloader/source.rb +20 -9
  54. data/lib/graphql/dataloader.rb +153 -45
  55. data/lib/graphql/date_encoding_error.rb +1 -1
  56. data/lib/graphql/dig.rb +2 -1
  57. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  58. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  59. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  60. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
  61. data/lib/graphql/execution/interpreter/runtime.rb +321 -222
  62. data/lib/graphql/execution/interpreter.rb +23 -30
  63. data/lib/graphql/execution/lookahead.rb +18 -11
  64. data/lib/graphql/execution/multiplex.rb +6 -5
  65. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  66. data/lib/graphql/introspection/directive_type.rb +1 -1
  67. data/lib/graphql/introspection/entry_points.rb +2 -2
  68. data/lib/graphql/introspection/field_type.rb +1 -1
  69. data/lib/graphql/introspection/schema_type.rb +6 -11
  70. data/lib/graphql/introspection/type_type.rb +5 -5
  71. data/lib/graphql/invalid_name_error.rb +1 -1
  72. data/lib/graphql/invalid_null_error.rb +20 -17
  73. data/lib/graphql/language/cache.rb +13 -0
  74. data/lib/graphql/language/comment.rb +18 -0
  75. data/lib/graphql/language/document_from_schema_definition.rb +64 -35
  76. data/lib/graphql/language/lexer.rb +72 -42
  77. data/lib/graphql/language/nodes.rb +93 -52
  78. data/lib/graphql/language/parser.rb +168 -61
  79. data/lib/graphql/language/printer.rb +31 -15
  80. data/lib/graphql/language/sanitized_printer.rb +1 -1
  81. data/lib/graphql/language.rb +61 -1
  82. data/lib/graphql/pagination/connection.rb +1 -1
  83. data/lib/graphql/query/context/scoped_context.rb +1 -1
  84. data/lib/graphql/query/context.rb +46 -47
  85. data/lib/graphql/query/null_context.rb +3 -5
  86. data/lib/graphql/query/partial.rb +179 -0
  87. data/lib/graphql/query/validation_pipeline.rb +2 -2
  88. data/lib/graphql/query/variable_validation_error.rb +1 -1
  89. data/lib/graphql/query.rb +123 -69
  90. data/lib/graphql/railtie.rb +7 -0
  91. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  92. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  93. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  94. data/lib/graphql/rubocop.rb +2 -0
  95. data/lib/graphql/schema/addition.rb +26 -13
  96. data/lib/graphql/schema/always_visible.rb +7 -2
  97. data/lib/graphql/schema/argument.rb +57 -8
  98. data/lib/graphql/schema/build_from_definition.rb +116 -49
  99. data/lib/graphql/schema/directive/flagged.rb +4 -2
  100. data/lib/graphql/schema/directive.rb +54 -2
  101. data/lib/graphql/schema/enum.rb +107 -24
  102. data/lib/graphql/schema/enum_value.rb +10 -2
  103. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  104. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  105. data/lib/graphql/schema/field.rb +134 -45
  106. data/lib/graphql/schema/field_extension.rb +1 -1
  107. data/lib/graphql/schema/has_single_input_argument.rb +6 -2
  108. data/lib/graphql/schema/input_object.rb +122 -64
  109. data/lib/graphql/schema/interface.rb +23 -5
  110. data/lib/graphql/schema/introspection_system.rb +6 -17
  111. data/lib/graphql/schema/late_bound_type.rb +4 -0
  112. data/lib/graphql/schema/list.rb +3 -3
  113. data/lib/graphql/schema/loader.rb +3 -2
  114. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  115. data/lib/graphql/schema/member/has_arguments.rb +44 -58
  116. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  117. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  118. data/lib/graphql/schema/member/has_directives.rb +4 -4
  119. data/lib/graphql/schema/member/has_fields.rb +26 -6
  120. data/lib/graphql/schema/member/has_interfaces.rb +6 -6
  121. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  122. data/lib/graphql/schema/member/has_validators.rb +1 -1
  123. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  124. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  125. data/lib/graphql/schema/member.rb +1 -0
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +25 -8
  128. data/lib/graphql/schema/printer.rb +1 -0
  129. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  130. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  131. data/lib/graphql/schema/resolver.rb +29 -23
  132. data/lib/graphql/schema/scalar.rb +1 -6
  133. data/lib/graphql/schema/subscription.rb +52 -6
  134. data/lib/graphql/schema/timeout.rb +19 -2
  135. data/lib/graphql/schema/type_expression.rb +2 -2
  136. data/lib/graphql/schema/union.rb +1 -1
  137. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  138. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  139. data/lib/graphql/schema/validator.rb +3 -1
  140. data/lib/graphql/schema/visibility/migration.rb +188 -0
  141. data/lib/graphql/schema/visibility/profile.rb +445 -0
  142. data/lib/graphql/schema/visibility/visit.rb +190 -0
  143. data/lib/graphql/schema/visibility.rb +311 -0
  144. data/lib/graphql/schema/warden.rb +190 -20
  145. data/lib/graphql/schema.rb +695 -167
  146. data/lib/graphql/static_validation/all_rules.rb +2 -2
  147. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  148. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  149. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  150. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  151. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  152. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  153. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  154. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  155. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  156. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  157. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  158. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  159. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  160. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  161. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  162. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  163. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  164. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  165. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  166. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  167. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  168. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  169. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  170. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  171. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  172. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  173. data/lib/graphql/static_validation/validation_context.rb +18 -2
  174. data/lib/graphql/static_validation/validator.rb +6 -1
  175. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
  176. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  177. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  178. data/lib/graphql/subscriptions/event.rb +13 -2
  179. data/lib/graphql/subscriptions/serialize.rb +1 -1
  180. data/lib/graphql/subscriptions.rb +7 -5
  181. data/lib/graphql/testing/helpers.rb +48 -16
  182. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  183. data/lib/graphql/testing.rb +1 -0
  184. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  185. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  186. data/lib/graphql/tracing/appoptics_trace.rb +5 -1
  187. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  188. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  189. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  190. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  191. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  192. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  193. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  194. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  195. data/lib/graphql/tracing/detailed_trace.rb +141 -0
  196. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  197. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  198. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  199. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  200. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  201. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  202. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  203. data/lib/graphql/tracing/null_trace.rb +9 -0
  204. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  205. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  206. data/lib/graphql/tracing/perfetto_trace.rb +818 -0
  207. data/lib/graphql/tracing/platform_tracing.rb +1 -1
  208. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  209. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  210. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  211. data/lib/graphql/tracing/scout_trace.rb +32 -58
  212. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  213. data/lib/graphql/tracing/sentry_trace.rb +64 -98
  214. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  215. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  216. data/lib/graphql/tracing/trace.rb +111 -1
  217. data/lib/graphql/tracing.rb +31 -30
  218. data/lib/graphql/type_kinds.rb +2 -1
  219. data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
  220. data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
  221. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  222. data/lib/graphql/types.rb +18 -11
  223. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  224. data/lib/graphql/version.rb +1 -1
  225. data/lib/graphql.rb +64 -54
  226. metadata +197 -22
  227. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  228. data/lib/graphql/analysis/ast/field_usage.rb +0 -82
  229. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  230. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  231. data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
  232. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  233. data/lib/graphql/analysis/ast.rb +0 -94
  234. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  235. data/lib/graphql/backtrace/trace.rb +0 -93
  236. data/lib/graphql/backtrace/tracer.rb +0 -80
  237. data/lib/graphql/language/token.rb +0 -34
  238. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  239. data/lib/graphql/schema/null_mask.rb +0 -11
  240. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -22,9 +22,21 @@ module GraphQL
22
22
  class Enum < GraphQL::Schema::Member
23
23
  extend GraphQL::Schema::Member::ValidatesInput
24
24
 
25
+ # This is raised when either:
26
+ #
27
+ # - A resolver returns a value which doesn't match any of the enum's configured values;
28
+ # - Or, the resolver returns a value which matches a value, but that value's `authorized?` check returns false.
29
+ #
30
+ # In either case, the field should be modified so that the invalid value isn't returned.
31
+ #
32
+ # {GraphQL::Schema::Enum} subclasses get their own subclass of this error, so that bug trackers can better show where they came from.
25
33
  class UnresolvedValueError < GraphQL::Error
26
- def initialize(value:, enum:, context:)
27
- fix_message = ", but this isn't a valid value for `#{enum.graphql_name}`. Update the field or resolver to return one of `#{enum.graphql_name}`'s values instead."
34
+ def initialize(value:, enum:, context:, authorized:)
35
+ fix_message = if authorized == false
36
+ ", but this value was unauthorized. Update the field or resolver to return a different value in this case (or return `nil`)."
37
+ else
38
+ ", but this isn't a valid value for `#{enum.graphql_name}`. Update the field or resolver to return one of `#{enum.graphql_name}`'s values instead."
39
+ end
28
40
  message = if (cp = context[:current_path]) && (cf = context[:current_field])
29
41
  "`#{cf.path}` returned `#{value.inspect}` at `#{cp.join(".")}`#{fix_message}"
30
42
  else
@@ -34,6 +46,8 @@ module GraphQL
34
46
  end
35
47
  end
36
48
 
49
+ # Raised when a {GraphQL::Schema::Enum} is defined to have no values.
50
+ # This can also happen when all values return false for `.visible?`.
37
51
  class MissingValuesError < GraphQL::Error
38
52
  def initialize(enum_type)
39
53
  @enum_type = enum_type
@@ -43,15 +57,23 @@ module GraphQL
43
57
 
44
58
  class << self
45
59
  # Define a value for this enum
46
- # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
47
- # @param description [String], the GraphQL description for this value, present in documentation
48
- # @param value [Object], the translated Ruby value for this object (defaults to `graphql_name`)
49
- # @param deprecation_reason [String] if this object is deprecated, include a message here
60
+ # @option kwargs [String, Symbol] :graphql_name the GraphQL value for this, usually `SCREAMING_CASE`
61
+ # @option kwargs [String] :description, the GraphQL description for this value, present in documentation
62
+ # @option kwargs [String] :comment, the GraphQL comment for this value, present in documentation
63
+ # @option kwargs [::Object] :value the translated Ruby value for this object (defaults to `graphql_name`)
64
+ # @option kwargs [::Object] :value_method, the method name to fetch `graphql_name` (defaults to `graphql_name.downcase`)
65
+ # @option kwargs [String] :deprecation_reason if this object is deprecated, include a message here
66
+ # @param value_method [Symbol, false] A method to generate for this value, or `false` to skip generation
50
67
  # @return [void]
51
68
  # @see {Schema::EnumValue} which handles these inputs by default
52
- def value(*args, **kwargs, &block)
69
+ def value(*args, value_method: nil, **kwargs, &block)
53
70
  kwargs[:owner] = self
54
71
  value = enum_value_class.new(*args, **kwargs, &block)
72
+
73
+ if value_method || (value_methods && value_method != false)
74
+ generate_value_method(value, value_method)
75
+ end
76
+
55
77
  key = value.graphql_name
56
78
  prev_value = own_values[key]
57
79
  case prev_value
@@ -71,10 +93,24 @@ module GraphQL
71
93
  def enum_values(context = GraphQL::Query::NullContext.instance)
72
94
  inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
73
95
  visible_values = []
74
- warden = Warden.from_context(context)
96
+ types = Warden.types_from_context(context)
75
97
  own_values.each do |key, values_entry|
76
- if (v = Warden.visible_entry?(:visible_enum_value?, values_entry, context, warden))
77
- visible_values << v
98
+ visible_value = nil
99
+ if values_entry.is_a?(Array)
100
+ values_entry.each do |v|
101
+ if types.visible_enum_value?(v, context)
102
+ if visible_value.nil?
103
+ visible_value = v
104
+ visible_values << v
105
+ else
106
+ raise DuplicateNamesError.new(
107
+ duplicated_name: v.path, duplicated_definition_1: visible_value.inspect, duplicated_definition_2: v.inspect
108
+ )
109
+ end
110
+ end
111
+ end
112
+ elsif types.visible_enum_value?(values_entry, context)
113
+ visible_values << values_entry
78
114
  end
79
115
  end
80
116
 
@@ -125,12 +161,24 @@ module GraphQL
125
161
  end
126
162
  end
127
163
 
164
+ def value_methods(new_value = NOT_CONFIGURED)
165
+ if NOT_CONFIGURED.equal?(new_value)
166
+ if @value_methods != nil
167
+ @value_methods
168
+ else
169
+ find_inherited_value(:value_methods, false)
170
+ end
171
+ else
172
+ @value_methods = new_value
173
+ end
174
+ end
175
+
128
176
  def kind
129
177
  GraphQL::TypeKinds::ENUM
130
178
  end
131
179
 
132
180
  def validate_non_null_input(value_name, ctx, max_errors: nil)
133
- allowed_values = ctx.warden.enum_values(self)
181
+ allowed_values = ctx.types.enum_values(self)
134
182
  matching_value = allowed_values.find { |v| v.graphql_name == value_name }
135
183
 
136
184
  if matching_value.nil?
@@ -138,35 +186,55 @@ module GraphQL
138
186
  else
139
187
  nil
140
188
  end
189
+ # rescue MissingValuesError
190
+ # nil
141
191
  end
142
192
 
193
+ # Called by the runtime when a field returns a value to give back to the client.
194
+ # This method checks that the incoming {value} matches one of the enum's defined values.
195
+ # @param value [Object] Any value matching the values for this enum.
196
+ # @param ctx [GraphQL::Query::Context]
197
+ # @raise [GraphQL::Schema::Enum::UnresolvedValueError] if {value} doesn't match a configured value or if the matching value isn't authorized.
198
+ # @return [String] The GraphQL-ready string for {value}
143
199
  def coerce_result(value, ctx)
144
- warden = ctx.warden
145
- all_values = warden ? warden.enum_values(self) : values.each_value
200
+ types = ctx.types
201
+ all_values = types ? types.enum_values(self) : values.each_value
146
202
  enum_value = all_values.find { |val| val.value == value }
147
- if enum_value
203
+ if enum_value && (was_authed = enum_value.authorized?(ctx))
148
204
  enum_value.graphql_name
149
205
  else
150
- raise self::UnresolvedValueError.new(enum: self, value: value, context: ctx)
206
+ raise self::UnresolvedValueError.new(enum: self, value: value, context: ctx, authorized: was_authed)
151
207
  end
152
208
  end
153
209
 
210
+ # Called by the runtime with incoming string representations from a query.
211
+ # It will match the string to a configured by name or by Ruby value.
212
+ # @param value_name [String, Object] A string from a GraphQL query, or a Ruby value matching a `value(..., value: ...)` configuration
213
+ # @param ctx [GraphQL::Query::Context]
214
+ # @raise [GraphQL::UnauthorizedEnumValueError] if an {EnumValue} matches but returns false for `.authorized?`. Goes to {Schema.unauthorized_object}.
215
+ # @return [Object] The Ruby value for the matched {GraphQL::Schema::EnumValue}
154
216
  def coerce_input(value_name, ctx)
155
- all_values = ctx.warden ? ctx.warden.enum_values(self) : values.each_value
156
-
157
- if v = all_values.find { |val| val.graphql_name == value_name }
158
- v.value
159
- elsif v = all_values.find { |val| val.value == value_name }
160
- # this is for matching default values, which are "inputs", but they're
161
- # the Ruby value, not the GraphQL string.
162
- v.value
217
+ all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value
218
+
219
+ # This tries matching by incoming GraphQL string, then checks Ruby-defined values
220
+ if v = (all_values.find { |val| val.graphql_name == value_name } || all_values.find { |val| val.value == value_name })
221
+ if v.authorized?(ctx)
222
+ v.value
223
+ else
224
+ raise GraphQL::UnauthorizedEnumValueError.new(type: self, enum_value: v, context: ctx)
225
+ end
163
226
  else
164
227
  nil
165
228
  end
166
229
  end
167
230
 
168
231
  def inherited(child_class)
169
- child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
232
+ if child_class.name
233
+ # Don't assign a custom error class to anonymous classes
234
+ # because they would end up with names like `#<Class0x1234>::UnresolvedValueError` which messes up bug trackers
235
+ child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
236
+ end
237
+ child_class.class_exec { @value_methods = nil }
170
238
  super
171
239
  end
172
240
 
@@ -175,6 +243,21 @@ module GraphQL
175
243
  def own_values
176
244
  @own_values ||= {}
177
245
  end
246
+
247
+ def generate_value_method(value, configured_value_method)
248
+ return if configured_value_method == false
249
+
250
+ value_method_name = configured_value_method || value.graphql_name.downcase
251
+
252
+ if respond_to?(value_method_name.to_sym)
253
+ warn "Failed to define value method for :#{value_method_name}, because " \
254
+ "#{value.owner.name || value.owner.graphql_name} already responds to that method. Use `value_method:` to override the method name " \
255
+ "or `value_method: false` to disable Enum value method generation."
256
+ return
257
+ end
258
+
259
+ define_singleton_method(value_method_name) { value.graphql_name }
260
+ end
178
261
  end
179
262
 
180
263
  enum_value_class(GraphQL::Schema::EnumValue)
@@ -30,10 +30,11 @@ module GraphQL
30
30
  # @return [Class] The enum type that owns this value
31
31
  attr_reader :owner
32
32
 
33
- def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: NOT_CONFIGURED, deprecation_reason: nil, &block)
33
+ def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, comment: nil, value: NOT_CONFIGURED, deprecation_reason: nil, &block)
34
34
  @graphql_name = graphql_name.to_s
35
35
  GraphQL::NameValidator.validate!(@graphql_name)
36
36
  @description = desc || description
37
+ @comment = comment
37
38
  @value = value == NOT_CONFIGURED ? @graphql_name : value
38
39
  if deprecation_reason
39
40
  self.deprecation_reason = deprecation_reason
@@ -58,6 +59,13 @@ module GraphQL
58
59
  @description
59
60
  end
60
61
 
62
+ def comment(new_comment = nil)
63
+ if new_comment
64
+ @comment = new_comment
65
+ end
66
+ @comment
67
+ end
68
+
61
69
  def value(new_val = nil)
62
70
  unless new_val.nil?
63
71
  @value = new_val
@@ -66,7 +74,7 @@ module GraphQL
66
74
  end
67
75
 
68
76
  def inspect
69
- "#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}>"
77
+ "#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}#{deprecation_reason ? " @deprecation_reason=#{deprecation_reason.inspect}" : ""}>"
70
78
  end
71
79
 
72
80
  def visible?(_ctx); true; end
@@ -50,7 +50,7 @@ module GraphQL
50
50
  if field.has_default_page_size? && !value.has_default_page_size_override?
51
51
  value.default_page_size = field.default_page_size
52
52
  end
53
- if context.schema.new_connections? && (custom_t = context.schema.connections.edge_class_for_field(@field))
53
+ if (custom_t = context.schema.connections.edge_class_for_field(@field))
54
54
  value.edge_class = custom_t
55
55
  end
56
56
  value
@@ -12,7 +12,7 @@ module GraphQL
12
12
  if ret_type.respond_to?(:scope_items)
13
13
  scoped_items = ret_type.scope_items(value, context)
14
14
  if !scoped_items.equal?(value) && !ret_type.reauthorize_scoped_objects
15
- if (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
15
+ if (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
16
16
  (query_runtime_state = current_runtime_state[context.query])
17
17
  query_runtime_state.was_authorized_by_scope_items = true
18
18
  end
@@ -41,6 +41,32 @@ module GraphQL
41
41
  end
42
42
  end
43
43
 
44
+ # @return [String, nil]
45
+ def deprecation_reason
46
+ super || @resolver_class&.deprecation_reason
47
+ end
48
+
49
+ def directives
50
+ if @resolver_class && !(r_dirs = @resolver_class.directives).empty?
51
+ if !(own_dirs = super).empty?
52
+ new_dirs = own_dirs.dup
53
+ r_dirs.each do |r_dir|
54
+ if r_dir.class.repeatable? ||
55
+ ( (r_dir_name = r_dir.graphql_name) &&
56
+ (!new_dirs.any? { |d| d.graphql_name == r_dir_name })
57
+ )
58
+ new_dirs << r_dir
59
+ end
60
+ end
61
+ new_dirs
62
+ else
63
+ r_dirs
64
+ end
65
+ else
66
+ super
67
+ end
68
+ end
69
+
44
70
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
45
71
  attr_accessor :owner
46
72
 
@@ -69,7 +95,7 @@ module GraphQL
69
95
  end
70
96
 
71
97
  def inspect
72
- "#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
98
+ "#<#{self.class} #{path}#{!all_argument_definitions.empty? ? "(...)" : ""}: #{type.to_type_signature}>"
73
99
  end
74
100
 
75
101
  alias :mutation :resolver
@@ -94,7 +120,7 @@ module GraphQL
94
120
  # @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
95
121
  # @return [GraphQL::Schema:Field] an instance of `self`
96
122
  # @see {.initialize} for other options
97
- def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
123
+ def self.from_options(name = nil, type = nil, desc = nil, comment: nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
98
124
  if (resolver_class = resolver || mutation || subscription)
99
125
  # Add a reference to that parent class
100
126
  kwargs[:resolver_class] = resolver_class
@@ -104,6 +130,10 @@ module GraphQL
104
130
  kwargs[:name] = name
105
131
  end
106
132
 
133
+ if comment
134
+ kwargs[:comment] = comment
135
+ end
136
+
107
137
  if !type.nil?
108
138
  if desc
109
139
  if kwargs[:description]
@@ -134,11 +164,16 @@ module GraphQL
134
164
  Member::BuildType.to_type_name(@return_type_expr)
135
165
  elsif @resolver_class && @resolver_class.type
136
166
  Member::BuildType.to_type_name(@resolver_class.type)
137
- else
167
+ elsif type
138
168
  # As a last ditch, try to force loading the return type:
139
169
  type.unwrap.name
140
170
  end
141
- @connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
171
+ if return_type_name
172
+ @connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
173
+ else
174
+ # TODO set this when type is set by method
175
+ false # not loaded yet?
176
+ end
142
177
  else
143
178
  @connection
144
179
  end
@@ -195,6 +230,7 @@ module GraphQL
195
230
  # @param owner [Class] The type that this field belongs to
196
231
  # @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
197
232
  # @param description [String] Field description
233
+ # @param comment [String] Field comment
198
234
  # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
199
235
  # @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
200
236
  # @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
@@ -219,13 +255,13 @@ module GraphQL
219
255
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
220
256
  # @param validates [Array<Hash>] Configurations for validating this field
221
257
  # @param fallback_value [Object] A fallback value if the method is not defined
222
- def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
258
+ def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, comment: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
223
259
  if name.nil?
224
260
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
225
261
  end
226
262
  if !(resolver_class)
227
- if type.nil?
228
- raise ArgumentError, "missing second `type` argument or keyword `type:`"
263
+ if type.nil? && !block_given?
264
+ raise ArgumentError, "missing second `type` argument, keyword `type:`, or a block containing `type(...)`"
229
265
  end
230
266
  end
231
267
  @original_name = name
@@ -235,6 +271,7 @@ module GraphQL
235
271
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
236
272
  NameValidator.validate!(@name)
237
273
  @description = description
274
+ @comment = comment
238
275
  @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
239
276
 
240
277
  self.deprecation_reason = deprecation_reason
@@ -290,6 +327,7 @@ module GraphQL
290
327
  @ast_node = ast_node
291
328
  @method_conflict_warning = method_conflict_warning
292
329
  @fallback_value = fallback_value
330
+ @definition_block = definition_block
293
331
 
294
332
  arguments.each do |name, arg|
295
333
  case arg
@@ -309,28 +347,17 @@ module GraphQL
309
347
 
310
348
  @extensions = EMPTY_ARRAY
311
349
  @call_after_define = false
312
- # This should run before connection extension,
313
- # but should it run after the definition block?
314
- if scoped?
315
- self.extension(ScopeExtension)
316
- end
317
-
318
- # The problem with putting this after the definition_block
319
- # is that it would override arguments
320
- if connection? && connection_extension
321
- self.extension(connection_extension)
322
- end
323
-
350
+ set_pagination_extensions(connection_extension: connection_extension)
324
351
  # Do this last so we have as much context as possible when initializing them:
325
- if extensions.any?
352
+ if !extensions.empty?
326
353
  self.extensions(extensions)
327
354
  end
328
355
 
329
- if resolver_class && resolver_class.extensions.any?
356
+ if resolver_class && !resolver_class.extensions.empty?
330
357
  self.extensions(resolver_class.extensions)
331
358
  end
332
359
 
333
- if directives.any?
360
+ if !directives.empty?
334
361
  directives.each do |(dir_class, options)|
335
362
  self.directive(dir_class, **options)
336
363
  end
@@ -340,16 +367,29 @@ module GraphQL
340
367
  self.validates(validates)
341
368
  end
342
369
 
343
- if block_given?
344
- if definition_block.arity == 1
345
- yield self
370
+ if @definition_block.nil?
371
+ self.extensions.each(&:after_define_apply)
372
+ @call_after_define = true
373
+ end
374
+ end
375
+
376
+ # Calls the definition block, if one was given.
377
+ # This is deferred so that references to the return type
378
+ # can be lazily evaluated, reducing Rails boot time.
379
+ # @return [self]
380
+ # @api private
381
+ def ensure_loaded
382
+ if @definition_block
383
+ if @definition_block.arity == 1
384
+ @definition_block.call(self)
346
385
  else
347
- instance_eval(&definition_block)
386
+ instance_exec(self, &@definition_block)
348
387
  end
388
+ self.extensions.each(&:after_define_apply)
389
+ @call_after_define = true
390
+ @definition_block = nil
349
391
  end
350
-
351
- self.extensions.each(&:after_define_apply)
352
- @call_after_define = true
392
+ self
353
393
  end
354
394
 
355
395
  attr_accessor :dynamic_introspection
@@ -381,6 +421,20 @@ module GraphQL
381
421
  end
382
422
  end
383
423
 
424
+ # @param text [String]
425
+ # @return [String, nil]
426
+ def comment(text = nil)
427
+ if text
428
+ @comment = text
429
+ elsif !NOT_CONFIGURED.equal?(@comment)
430
+ @comment
431
+ elsif @resolver_class
432
+ @resolver_class.comment
433
+ else
434
+ nil
435
+ end
436
+ end
437
+
384
438
  # Read extension instances from this field,
385
439
  # or add new classes/options to be initialized on this field.
386
440
  # Extensions are executed in the order they are added.
@@ -401,7 +455,7 @@ module GraphQL
401
455
  new_extensions.each do |extension_config|
402
456
  if extension_config.is_a?(Hash)
403
457
  extension_class, options = *extension_config.to_a[0]
404
- self.extension(extension_class, options)
458
+ self.extension(extension_class, **options)
405
459
  else
406
460
  self.extension(extension_config)
407
461
  end
@@ -421,7 +475,7 @@ module GraphQL
421
475
  # @param extension_class [Class] subclass of {Schema::FieldExtension}
422
476
  # @param options [Hash] if provided, given as `options:` when initializing `extension`.
423
477
  # @return [void]
424
- def extension(extension_class, options = nil)
478
+ def extension(extension_class, **options)
425
479
  extension_inst = extension_class.new(field: self, options: options)
426
480
  if @extensions.frozen?
427
481
  @extensions = @extensions.dup
@@ -442,7 +496,7 @@ module GraphQL
442
496
  if new_extras.nil?
443
497
  # Read the value
444
498
  field_extras = @extras
445
- if @resolver_class && @resolver_class.extras.any?
499
+ if @resolver_class && !@resolver_class.extras.empty?
446
500
  field_extras + @resolver_class.extras
447
501
  else
448
502
  field_extras
@@ -471,7 +525,7 @@ module GraphQL
471
525
  if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
472
526
  max_possible_page_size = arguments[:last]
473
527
  end
474
- elsif arguments.is_a?(GraphQL::UnauthorizedError)
528
+ elsif arguments.is_a?(GraphQL::ExecutionError) || arguments.is_a?(GraphQL::UnauthorizedError)
475
529
  raise arguments
476
530
  end
477
531
 
@@ -562,19 +616,40 @@ module GraphQL
562
616
  end
563
617
  end
564
618
 
619
+ def freeze
620
+ type
621
+ owner_type
622
+ arguments_statically_coercible?
623
+ connection?
624
+ super
625
+ end
626
+
565
627
  class MissingReturnTypeError < GraphQL::Error; end
566
628
  attr_writer :type
567
629
 
568
- def type
569
- if @resolver_class
570
- return_type = @return_type_expr || @resolver_class.type_expr
571
- if return_type.nil?
572
- raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
630
+ # Get or set the return type of this field.
631
+ #
632
+ # It may return nil if no type was configured or if the given definition block wasn't called yet.
633
+ # @param new_type [Module, GraphQL::Schema::NonNull, GraphQL::Schema::List] A GraphQL return type
634
+ # @return [Module, GraphQL::Schema::NonNull, GraphQL::Schema::List, nil] the configured type for this field
635
+ def type(new_type = NOT_CONFIGURED)
636
+ if NOT_CONFIGURED.equal?(new_type)
637
+ if @resolver_class
638
+ return_type = @return_type_expr || @resolver_class.type_expr
639
+ if return_type.nil?
640
+ raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
641
+ end
642
+ nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
643
+ Member::BuildType.parse_type(return_type, null: nullable)
644
+ elsif !@return_type_expr.nil?
645
+ @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
573
646
  end
574
- nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
575
- Member::BuildType.parse_type(return_type, null: nullable)
576
647
  else
577
- @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
648
+ @return_type_expr = new_type
649
+ # If `type` is set in the definition block, then the `connection_extension: ...` given as a keyword won't be used, hmm...
650
+ # Also, arguments added by `connection_extension` will clobber anything previously defined,
651
+ # so `type(...)` should go first.
652
+ set_pagination_extensions(connection_extension: self.class.connection_extension)
578
653
  end
579
654
  rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
580
655
  # Let this propagate up
@@ -606,7 +681,7 @@ module GraphQL
606
681
  using_arg_values = false
607
682
  end
608
683
 
609
- args = context.warden.arguments(self)
684
+ args = context.types.arguments(self)
610
685
  args.each do |arg|
611
686
  arg_key = arg.keyword
612
687
  if arg_values.key?(arg_key)
@@ -679,7 +754,7 @@ module GraphQL
679
754
  method_to_call = resolver_method
680
755
  method_receiver = obj
681
756
  # Call the method with kwargs, if there are any
682
- if ruby_kwargs.any?
757
+ if !ruby_kwargs.empty?
683
758
  obj.public_send(resolver_method, **ruby_kwargs)
684
759
  else
685
760
  obj.public_send(resolver_method)
@@ -699,7 +774,7 @@ module GraphQL
699
774
  elsif inner_object.respond_to?(@method_sym)
700
775
  method_to_call = @method_sym
701
776
  method_receiver = obj.object
702
- if ruby_kwargs.any?
777
+ if !ruby_kwargs.empty?
703
778
  inner_object.public_send(@method_sym, **ruby_kwargs)
704
779
  else
705
780
  inner_object.public_send(@method_sym)
@@ -786,7 +861,7 @@ module GraphQL
786
861
  unsatisfied_ruby_kwargs.clear
787
862
  end
788
863
 
789
- if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
864
+ if !unsatisfied_ruby_kwargs.empty? || !unsatisfied_method_params.empty?
790
865
  raise FieldImplementationFailed.new, <<-ERR
791
866
  Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
792
867
 
@@ -885,6 +960,20 @@ ERR
885
960
  raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
886
961
  end
887
962
  end
963
+
964
+ def set_pagination_extensions(connection_extension:)
965
+ # This should run before connection extension,
966
+ # but should it run after the definition block?
967
+ if scoped?
968
+ self.extension(ScopeExtension, call_after_define: false)
969
+ end
970
+
971
+ # The problem with putting this after the definition_block
972
+ # is that it would override arguments
973
+ if connection? && connection_extension
974
+ self.extension(connection_extension, call_after_define: false)
975
+ end
976
+ end
888
977
  end
889
978
  end
890
979
  end
@@ -104,7 +104,7 @@ module GraphQL
104
104
  end
105
105
  end
106
106
  end
107
- if (extras = self.class.extras).any?
107
+ if !(extras = self.class.extras).empty?
108
108
  @added_extras = extras - field.extras
109
109
  field.extras(@added_extras)
110
110
  else
@@ -32,7 +32,7 @@ module GraphQL
32
32
  input_kwargs = {}
33
33
  end
34
34
 
35
- if input_kwargs.any?
35
+ if !input_kwargs.empty?
36
36
  super(**input_kwargs)
37
37
  else
38
38
  super()
@@ -47,6 +47,7 @@ module GraphQL
47
47
  def dummy
48
48
  @dummy ||= begin
49
49
  d = Class.new(GraphQL::Schema::Resolver)
50
+ d.graphql_name "#{self.graphql_name}DummyResolver"
50
51
  d.argument_class(self.argument_class)
51
52
  # TODO make this lazier?
52
53
  d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
@@ -135,6 +136,8 @@ module GraphQL
135
136
  super || "Autogenerated input type of #{self.mutation.graphql_name}"
136
137
  end
137
138
  end
139
+ # For compatibility, in case no arguments are defined:
140
+ has_no_arguments(true)
138
141
  mutation(mutation_class)
139
142
  # these might be inherited:
140
143
  mutation_args.each do |arg|
@@ -148,7 +151,8 @@ module GraphQL
148
151
 
149
152
  def authorize_arguments(args, values)
150
153
  # remove the `input` wrapper to match values
151
- input_args = args["input"].type.unwrap.arguments(context)
154
+ input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
155
+ input_args = context.types.arguments(input_type)
152
156
  super(input_args, values)
153
157
  end
154
158
  end