graphql 1.13.14 → 2.0.19

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/relay.rb +3 -17
  4. data/lib/generators/graphql/templates/schema.erb +3 -0
  5. data/lib/graphql/analysis/ast/field_usage.rb +3 -1
  6. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  7. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  8. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  9. data/lib/graphql/analysis/ast/visitor.rb +43 -36
  10. data/lib/graphql/analysis/ast.rb +2 -12
  11. data/lib/graphql/analysis.rb +0 -7
  12. data/lib/graphql/backtrace/table.rb +2 -20
  13. data/lib/graphql/backtrace/tracer.rb +2 -3
  14. data/lib/graphql/backtrace.rb +2 -8
  15. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  16. data/lib/graphql/dataloader/source.rb +9 -0
  17. data/lib/graphql/dataloader.rb +4 -1
  18. data/lib/graphql/dig.rb +1 -1
  19. data/lib/graphql/execution/errors.rb +12 -82
  20. data/lib/graphql/execution/interpreter/resolve.rb +26 -0
  21. data/lib/graphql/execution/interpreter/runtime.rb +163 -120
  22. data/lib/graphql/execution/interpreter.rb +187 -78
  23. data/lib/graphql/execution/lazy.rb +7 -21
  24. data/lib/graphql/execution/lookahead.rb +44 -40
  25. data/lib/graphql/execution/multiplex.rb +3 -174
  26. data/lib/graphql/execution.rb +11 -4
  27. data/lib/graphql/introspection/directive_type.rb +2 -2
  28. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  29. data/lib/graphql/introspection/entry_points.rb +2 -15
  30. data/lib/graphql/introspection/field_type.rb +1 -1
  31. data/lib/graphql/introspection/schema_type.rb +2 -2
  32. data/lib/graphql/introspection/type_type.rb +13 -6
  33. data/lib/graphql/introspection.rb +4 -3
  34. data/lib/graphql/language/document_from_schema_definition.rb +18 -35
  35. data/lib/graphql/language/lexer.rb +216 -1488
  36. data/lib/graphql/language/lexer.ri +744 -0
  37. data/lib/graphql/language/nodes.rb +41 -33
  38. data/lib/graphql/language/parser.rb +375 -363
  39. data/lib/graphql/language/parser.y +48 -43
  40. data/lib/graphql/language/printer.rb +37 -21
  41. data/lib/graphql/language/visitor.rb +191 -83
  42. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  43. data/lib/graphql/pagination/array_connection.rb +4 -2
  44. data/lib/graphql/pagination/connection.rb +31 -4
  45. data/lib/graphql/pagination/connections.rb +3 -28
  46. data/lib/graphql/pagination/relation_connection.rb +2 -0
  47. data/lib/graphql/query/context.rb +155 -196
  48. data/lib/graphql/query/input_validation_result.rb +10 -1
  49. data/lib/graphql/query/null_context.rb +0 -3
  50. data/lib/graphql/query/validation_pipeline.rb +12 -37
  51. data/lib/graphql/query/variable_validation_error.rb +2 -2
  52. data/lib/graphql/query/variables.rb +35 -21
  53. data/lib/graphql/query.rb +32 -43
  54. data/lib/graphql/railtie.rb +0 -104
  55. data/lib/graphql/rake_task/validate.rb +1 -1
  56. data/lib/graphql/rake_task.rb +29 -1
  57. data/lib/graphql/relay/range_add.rb +9 -20
  58. data/lib/graphql/relay.rb +0 -15
  59. data/lib/graphql/schema/addition.rb +7 -9
  60. data/lib/graphql/schema/argument.rb +36 -43
  61. data/lib/graphql/schema/build_from_definition.rb +32 -18
  62. data/lib/graphql/schema/directive/one_of.rb +12 -0
  63. data/lib/graphql/schema/directive/transform.rb +1 -1
  64. data/lib/graphql/schema/directive.rb +12 -23
  65. data/lib/graphql/schema/enum.rb +29 -41
  66. data/lib/graphql/schema/enum_value.rb +5 -25
  67. data/lib/graphql/schema/field/connection_extension.rb +4 -0
  68. data/lib/graphql/schema/field.rb +245 -343
  69. data/lib/graphql/schema/input_object.rb +57 -69
  70. data/lib/graphql/schema/interface.rb +0 -35
  71. data/lib/graphql/schema/introspection_system.rb +3 -8
  72. data/lib/graphql/schema/late_bound_type.rb +8 -2
  73. data/lib/graphql/schema/list.rb +18 -9
  74. data/lib/graphql/schema/loader.rb +1 -2
  75. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  76. data/lib/graphql/schema/member/build_type.rb +5 -7
  77. data/lib/graphql/schema/member/has_arguments.rb +146 -55
  78. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  79. data/lib/graphql/schema/member/has_directives.rb +71 -56
  80. data/lib/graphql/schema/member/has_fields.rb +16 -4
  81. data/lib/graphql/schema/member/has_interfaces.rb +49 -10
  82. data/lib/graphql/schema/member/has_validators.rb +31 -5
  83. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  84. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  85. data/lib/graphql/schema/member/validates_input.rb +3 -3
  86. data/lib/graphql/schema/member.rb +0 -6
  87. data/lib/graphql/schema/mutation.rb +0 -9
  88. data/lib/graphql/schema/non_null.rb +3 -9
  89. data/lib/graphql/schema/object.rb +15 -52
  90. data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
  91. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  92. data/lib/graphql/schema/resolver.rb +41 -42
  93. data/lib/graphql/schema/scalar.rb +8 -23
  94. data/lib/graphql/schema/subscription.rb +0 -7
  95. data/lib/graphql/schema/timeout.rb +24 -28
  96. data/lib/graphql/schema/type_membership.rb +3 -0
  97. data/lib/graphql/schema/union.rb +10 -17
  98. data/lib/graphql/schema/warden.rb +34 -8
  99. data/lib/graphql/schema/wrapper.rb +0 -5
  100. data/lib/graphql/schema.rb +240 -968
  101. data/lib/graphql/static_validation/all_rules.rb +1 -0
  102. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  103. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  104. data/lib/graphql/static_validation/error.rb +2 -2
  105. data/lib/graphql/static_validation/literal_validator.rb +19 -1
  106. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  107. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  108. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  109. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  110. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
  111. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  112. data/lib/graphql/static_validation/validator.rb +3 -25
  113. data/lib/graphql/static_validation.rb +0 -2
  114. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
  115. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  116. data/lib/graphql/subscriptions/event.rb +3 -8
  117. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  118. data/lib/graphql/subscriptions.rb +32 -20
  119. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  120. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  121. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  122. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  123. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  124. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  125. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  126. data/lib/graphql/tracing/platform_trace.rb +107 -0
  127. data/lib/graphql/tracing/platform_tracing.rb +26 -40
  128. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  129. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  130. data/lib/graphql/tracing/scout_trace.rb +72 -0
  131. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  132. data/lib/graphql/tracing.rb +136 -41
  133. data/lib/graphql/type_kinds.rb +6 -3
  134. data/lib/graphql/types/iso_8601_date.rb +4 -1
  135. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  136. data/lib/graphql/types/relay/base_connection.rb +16 -6
  137. data/lib/graphql/types/relay/connection_behaviors.rb +5 -25
  138. data/lib/graphql/types/relay/default_relay.rb +5 -9
  139. data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
  140. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  141. data/lib/graphql/types/relay.rb +0 -2
  142. data/lib/graphql/types/string.rb +1 -1
  143. data/lib/graphql/version.rb +1 -1
  144. data/lib/graphql.rb +11 -72
  145. metadata +31 -133
  146. data/lib/graphql/analysis/analyze_query.rb +0 -98
  147. data/lib/graphql/analysis/field_usage.rb +0 -45
  148. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  149. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  150. data/lib/graphql/analysis/query_complexity.rb +0 -88
  151. data/lib/graphql/analysis/query_depth.rb +0 -43
  152. data/lib/graphql/analysis/reducer_state.rb +0 -48
  153. data/lib/graphql/argument.rb +0 -131
  154. data/lib/graphql/authorization.rb +0 -82
  155. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  156. data/lib/graphql/backwards_compatibility.rb +0 -61
  157. data/lib/graphql/base_type.rb +0 -232
  158. data/lib/graphql/boolean_type.rb +0 -2
  159. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  160. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  161. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  162. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  163. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  164. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  165. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  166. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  167. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  168. data/lib/graphql/compatibility.rb +0 -5
  169. data/lib/graphql/define/assign_argument.rb +0 -12
  170. data/lib/graphql/define/assign_connection.rb +0 -13
  171. data/lib/graphql/define/assign_enum_value.rb +0 -18
  172. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  173. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  174. data/lib/graphql/define/assign_object_field.rb +0 -42
  175. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  176. data/lib/graphql/define/instance_definable.rb +0 -255
  177. data/lib/graphql/define/no_definition_error.rb +0 -7
  178. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  179. data/lib/graphql/define/type_definer.rb +0 -31
  180. data/lib/graphql/define.rb +0 -31
  181. data/lib/graphql/deprecated_dsl.rb +0 -55
  182. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  183. data/lib/graphql/directive/include_directive.rb +0 -2
  184. data/lib/graphql/directive/skip_directive.rb +0 -2
  185. data/lib/graphql/directive.rb +0 -107
  186. data/lib/graphql/enum_type.rb +0 -133
  187. data/lib/graphql/execution/execute.rb +0 -333
  188. data/lib/graphql/execution/flatten.rb +0 -40
  189. data/lib/graphql/execution/instrumentation.rb +0 -92
  190. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  191. data/lib/graphql/execution/typecast.rb +0 -50
  192. data/lib/graphql/field/resolve.rb +0 -59
  193. data/lib/graphql/field.rb +0 -226
  194. data/lib/graphql/float_type.rb +0 -2
  195. data/lib/graphql/function.rb +0 -128
  196. data/lib/graphql/id_type.rb +0 -2
  197. data/lib/graphql/input_object_type.rb +0 -138
  198. data/lib/graphql/int_type.rb +0 -2
  199. data/lib/graphql/interface_type.rb +0 -72
  200. data/lib/graphql/internal_representation/document.rb +0 -27
  201. data/lib/graphql/internal_representation/node.rb +0 -206
  202. data/lib/graphql/internal_representation/print.rb +0 -51
  203. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  204. data/lib/graphql/internal_representation/scope.rb +0 -88
  205. data/lib/graphql/internal_representation/visit.rb +0 -36
  206. data/lib/graphql/internal_representation.rb +0 -7
  207. data/lib/graphql/language/lexer.rl +0 -260
  208. data/lib/graphql/list_type.rb +0 -80
  209. data/lib/graphql/non_null_type.rb +0 -71
  210. data/lib/graphql/object_type.rb +0 -130
  211. data/lib/graphql/query/arguments.rb +0 -189
  212. data/lib/graphql/query/arguments_cache.rb +0 -24
  213. data/lib/graphql/query/executor.rb +0 -52
  214. data/lib/graphql/query/literal_input.rb +0 -136
  215. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  216. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  217. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  218. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  219. data/lib/graphql/query/serial_execution.rb +0 -40
  220. data/lib/graphql/relay/array_connection.rb +0 -83
  221. data/lib/graphql/relay/base_connection.rb +0 -189
  222. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  223. data/lib/graphql/relay/connection_resolve.rb +0 -43
  224. data/lib/graphql/relay/connection_type.rb +0 -54
  225. data/lib/graphql/relay/edge.rb +0 -27
  226. data/lib/graphql/relay/edge_type.rb +0 -19
  227. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  228. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  229. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  230. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  231. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  232. data/lib/graphql/relay/mutation/result.rb +0 -38
  233. data/lib/graphql/relay/mutation.rb +0 -106
  234. data/lib/graphql/relay/node.rb +0 -39
  235. data/lib/graphql/relay/page_info.rb +0 -7
  236. data/lib/graphql/relay/relation_connection.rb +0 -188
  237. data/lib/graphql/relay/type_extensions.rb +0 -32
  238. data/lib/graphql/scalar_type.rb +0 -91
  239. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  240. data/lib/graphql/schema/default_parse_error.rb +0 -10
  241. data/lib/graphql/schema/default_type_error.rb +0 -17
  242. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  243. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  244. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  245. data/lib/graphql/schema/middleware_chain.rb +0 -82
  246. data/lib/graphql/schema/possible_types.rb +0 -44
  247. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  248. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  249. data/lib/graphql/schema/traversal.rb +0 -228
  250. data/lib/graphql/schema/validation.rb +0 -313
  251. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  252. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  253. data/lib/graphql/string_type.rb +0 -2
  254. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  255. data/lib/graphql/tracing/opentelemetry_tracing.rb +0 -101
  256. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  257. data/lib/graphql/types/relay/node_field.rb +0 -24
  258. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  259. data/lib/graphql/union_type.rb +0 -115
  260. data/lib/graphql/upgrader/member.rb +0 -937
  261. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -5,9 +5,8 @@ require "graphql/schema/field/scope_extension"
5
5
  module GraphQL
6
6
  class Schema
7
7
  class Field
8
- include GraphQL::Schema::Member::CachedGraphQLDefinition
9
- include GraphQL::Schema::Member::AcceptsDefinition
10
8
  include GraphQL::Schema::Member::HasArguments
9
+ include GraphQL::Schema::Member::HasArguments::FieldConfigured
11
10
  include GraphQL::Schema::Member::HasAstNode
12
11
  include GraphQL::Schema::Member::HasPath
13
12
  include GraphQL::Schema::Member::HasValidators
@@ -30,8 +29,17 @@ module GraphQL
30
29
  # @return [String] Method or hash key on the underlying object to look up
31
30
  attr_reader :method_str
32
31
 
32
+ attr_reader :hash_key
33
+ attr_reader :dig_keys
34
+
33
35
  # @return [Symbol] The method on the type to look up
34
- attr_reader :resolver_method
36
+ def resolver_method
37
+ if @resolver_class
38
+ @resolver_class.resolver_method
39
+ else
40
+ @resolver_method
41
+ end
42
+ end
35
43
 
36
44
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
37
45
  attr_accessor :owner
@@ -70,7 +78,10 @@ module GraphQL
70
78
  attr_reader :trace
71
79
 
72
80
  # @return [String, nil]
73
- attr_accessor :subscription_scope
81
+ def subscription_scope
82
+ @subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
83
+ end
84
+ attr_writer :subscription_scope
74
85
 
75
86
  # Create a field instance from a list of arguments, keyword arguments, and a block.
76
87
  #
@@ -84,21 +95,9 @@ module GraphQL
84
95
  # @return [GraphQL::Schema:Field] an instance of `self
85
96
  # @see {.initialize} for other options
86
97
  def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
87
- if kwargs[:field]
88
- if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
89
- GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
90
- return GraphQL::Types::Relay::NodeField
91
- elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
92
- GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
93
- return GraphQL::Types::Relay::NodesField
94
- end
95
- end
96
-
97
- if (parent_config = resolver || mutation || subscription)
98
- # Get the parent config, merge in local overrides
99
- kwargs = parent_config.field_options.merge(kwargs)
98
+ if (resolver_class = resolver || mutation || subscription)
100
99
  # Add a reference to that parent class
101
- kwargs[:resolver_class] = parent_config
100
+ kwargs[:resolver_class] = resolver_class
102
101
  end
103
102
 
104
103
  if name
@@ -106,9 +105,6 @@ module GraphQL
106
105
  end
107
106
 
108
107
  if !type.nil?
109
- if type.is_a?(GraphQL::Field)
110
- raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
111
- end
112
108
  if desc
113
109
  if kwargs[:description]
114
110
  raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
@@ -116,8 +112,8 @@ module GraphQL
116
112
 
117
113
  kwargs[:description] = desc
118
114
  kwargs[:type] = type
119
- elsif (kwargs[:field] || kwargs[:function] || resolver || mutation) && type.is_a?(String)
120
- # The return type should be copied from `field` or `function`, and the second positional argument is the description
115
+ elsif (resolver || mutation) && type.is_a?(String)
116
+ # The return type should be copied from the resolver, and the second positional argument is the description
121
117
  kwargs[:description] = type
122
118
  else
123
119
  kwargs[:type] = type
@@ -134,10 +130,10 @@ module GraphQL
134
130
  def connection?
135
131
  if @connection.nil?
136
132
  # Provide default based on type name
137
- return_type_name = if (contains_type = @field || @function)
138
- Member::BuildType.to_type_name(contains_type.type)
139
- elsif @return_type_expr
133
+ return_type_name = if @return_type_expr
140
134
  Member::BuildType.to_type_name(@return_type_expr)
135
+ elsif @resolver_class && @resolver_class.type
136
+ Member::BuildType.to_type_name(@resolver_class.type)
141
137
  else
142
138
  # As a last ditch, try to force loading the return type:
143
139
  type.unwrap.name
@@ -153,8 +149,18 @@ module GraphQL
153
149
  if !@scope.nil?
154
150
  # The default was overridden
155
151
  @scope
152
+ elsif @return_type_expr
153
+ # Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
154
+ @return_type_expr.is_a?(Array) ||
155
+ (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
156
+ connection?
157
+ elsif @resolver_class
158
+ resolver_type = @resolver_class.type_expr
159
+ resolver_type.is_a?(Array) ||
160
+ (resolver_type.is_a?(String) && resolver_type.include?("[")) ||
161
+ connection?
156
162
  else
157
- @return_type_expr && (@return_type_expr.is_a?(Array) || (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) || connection?)
163
+ false
158
164
  end
159
165
  end
160
166
 
@@ -187,7 +193,7 @@ module GraphQL
187
193
  # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
188
194
  # @param type [Class, GraphQL::BaseType, Array] The return type of this field
189
195
  # @param owner [Class] The type that this field belongs to
190
- # @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
196
+ # @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
191
197
  # @param description [String] Field description
192
198
  # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
193
199
  # @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
@@ -197,10 +203,8 @@ module GraphQL
197
203
  # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
198
204
  # @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
199
205
  # @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
206
+ # @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
200
207
  # @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
201
- # @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
202
- # @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
203
- # @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
204
208
  # @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
205
209
  # @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
206
210
  # @param camelize [Boolean] If true, the field name will be camelized when building the schema
@@ -214,31 +218,25 @@ module GraphQL
214
218
  # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
215
219
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
216
220
  # @param validates [Array<Hash>] Configurations for validating this field
217
- # @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
218
- def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, 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: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
221
+ # @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_given, &definition_block)
219
223
  if name.nil?
220
224
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
221
225
  end
222
- if !(field || function || resolver_class)
226
+ if !(resolver_class)
223
227
  if type.nil?
224
228
  raise ArgumentError, "missing second `type` argument or keyword `type:`"
225
229
  end
226
230
  end
227
- if (field || function || resolve) && extras.any?
228
- raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
229
- end
230
231
  @original_name = name
231
232
  name_s = -name.to_s
233
+
232
234
  @underscored_name = -Member::BuildType.underscore(name_s)
233
235
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
236
+
234
237
  @description = description
235
- if field.is_a?(GraphQL::Schema::Field)
236
- raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
237
- else
238
- @field = field
239
- end
240
- @function = function
241
- @resolve = resolve
238
+ @type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
239
+
242
240
  self.deprecation_reason = deprecation_reason
243
241
 
244
242
  if method && hash_key && dig
@@ -255,20 +253,31 @@ module GraphQL
255
253
  end
256
254
  end
257
255
 
258
- # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
259
256
  method_name = method || hash_key || name_s
260
257
  @dig_keys = dig
261
- resolver_method ||= name_s.to_sym
258
+ if hash_key
259
+ @hash_key = hash_key
260
+ @hash_key_str = hash_key.to_s
261
+ else
262
+ @hash_key = NOT_CONFIGURED
263
+ @hash_key_str = NOT_CONFIGURED
264
+ end
262
265
 
263
266
  @method_str = -method_name.to_s
264
267
  @method_sym = method_name.to_sym
265
- @resolver_method = resolver_method
268
+ @resolver_method = (resolver_method || name_s).to_sym
266
269
  @complexity = complexity
267
270
  @return_type_expr = type
268
- @return_type_null = null
271
+ @return_type_null = if !null.nil?
272
+ null
273
+ elsif resolver_class
274
+ nil
275
+ else
276
+ true
277
+ end
269
278
  @connection = connection
270
- @has_max_page_size = max_page_size != :not_given
271
- @max_page_size = max_page_size == :not_given ? nil : max_page_size
279
+ @max_page_size = max_page_size
280
+ @default_page_size = default_page_size
272
281
  @introspection = introspection
273
282
  @extras = extras
274
283
  @broadcastable = broadcastable
@@ -279,7 +288,7 @@ module GraphQL
279
288
  @relay_nodes_field = relay_nodes_field
280
289
  @ast_node = ast_node
281
290
  @method_conflict_warning = method_conflict_warning
282
- @legacy_edge_class = legacy_edge_class
291
+ @fallback_value = fallback_value
283
292
 
284
293
  arguments.each do |name, arg|
285
294
  case arg
@@ -316,13 +325,19 @@ module GraphQL
316
325
  self.extensions(extensions)
317
326
  end
318
327
 
328
+ if resolver_class && resolver_class.extensions.any?
329
+ self.extensions(resolver_class.extensions)
330
+ end
331
+
319
332
  if directives.any?
320
333
  directives.each do |(dir_class, options)|
321
334
  self.directive(dir_class, **options)
322
335
  end
323
336
  end
324
337
 
325
- self.validates(validates)
338
+ if !validates.empty?
339
+ self.validates(validates)
340
+ end
326
341
 
327
342
  if definition_block
328
343
  if definition_block.arity == 1
@@ -340,7 +355,13 @@ module GraphQL
340
355
  # @return [Boolean, nil]
341
356
  # @see GraphQL::Subscriptions::BroadcastAnalyzer
342
357
  def broadcastable?
343
- @broadcastable
358
+ if !NOT_CONFIGURED.equal?(@broadcastable)
359
+ @broadcastable
360
+ elsif @resolver_class
361
+ @resolver_class.broadcastable?
362
+ else
363
+ nil
364
+ end
344
365
  end
345
366
 
346
367
  # @param text [String]
@@ -348,8 +369,12 @@ module GraphQL
348
369
  def description(text = nil)
349
370
  if text
350
371
  @description = text
351
- else
372
+ elsif !NOT_CONFIGURED.equal?(@description)
352
373
  @description
374
+ elsif @resolver_class
375
+ @resolver_class.description
376
+ else
377
+ nil
353
378
  end
354
379
  end
355
380
 
@@ -413,7 +438,12 @@ module GraphQL
413
438
  def extras(new_extras = nil)
414
439
  if new_extras.nil?
415
440
  # Read the value
416
- @extras
441
+ field_extras = @extras
442
+ if @resolver_class && @resolver_class.extras.any?
443
+ field_extras + @resolver_class.extras
444
+ else
445
+ field_extras
446
+ end
417
447
  else
418
448
  if @extras.frozen?
419
449
  @extras = @extras.dup
@@ -441,11 +471,11 @@ module GraphQL
441
471
  end
442
472
 
443
473
  if max_possible_page_size.nil?
444
- max_possible_page_size = max_page_size || query.schema.default_max_page_size
474
+ max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
445
475
  end
446
476
 
447
477
  if max_possible_page_size.nil?
448
- raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
478
+ raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
449
479
  else
450
480
  metadata_complexity = 0
451
481
  lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
@@ -473,7 +503,13 @@ module GraphQL
473
503
  case defined_complexity
474
504
  when Proc
475
505
  arguments = query.arguments_for(nodes.first, self)
476
- defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
506
+ if arguments.is_a?(GraphQL::ExecutionError)
507
+ return child_complexity
508
+ elsif arguments.respond_to?(:keyword_arguments)
509
+ arguments = arguments.keyword_arguments
510
+ end
511
+
512
+ defined_complexity.call(query.context, arguments, child_complexity)
477
513
  when Numeric
478
514
  defined_complexity + child_complexity
479
515
  else
@@ -496,7 +532,11 @@ module GraphQL
496
532
  when Numeric
497
533
  @complexity = new_complexity
498
534
  when nil
499
- @complexity
535
+ if @resolver_class
536
+ @complexity || @resolver_class.complexity || 1
537
+ else
538
+ @complexity || 1
539
+ end
500
540
  else
501
541
  raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
502
542
  end
@@ -504,105 +544,49 @@ module GraphQL
504
544
 
505
545
  # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
506
546
  def has_max_page_size?
507
- @has_max_page_size
547
+ !NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
508
548
  end
509
549
 
510
550
  # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
511
- attr_reader :max_page_size
512
-
513
- prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
514
-
515
- # @return [GraphQL::Field]
516
- def to_graphql
517
- field_defn = if @field
518
- @field.dup
519
- elsif @function
520
- GraphQL::Function.build_field(@function)
551
+ def max_page_size
552
+ if !NOT_CONFIGURED.equal?(@max_page_size)
553
+ @max_page_size
554
+ elsif @resolver_class && @resolver_class.has_max_page_size?
555
+ @resolver_class.max_page_size
521
556
  else
522
- GraphQL::Field.new
523
- end
524
-
525
- field_defn.name = @name
526
- if @return_type_expr
527
- field_defn.type = -> { type }
528
- end
529
-
530
- if @description
531
- field_defn.description = @description
532
- end
533
-
534
- if self.deprecation_reason
535
- field_defn.deprecation_reason = self.deprecation_reason
557
+ nil
536
558
  end
559
+ end
537
560
 
538
- if @resolver_class
539
- if @resolver_class < GraphQL::Schema::Mutation
540
- field_defn.mutation = @resolver_class
541
- end
542
- field_defn.metadata[:resolver] = @resolver_class
543
- end
544
-
545
- if !@trace.nil?
546
- field_defn.trace = @trace
547
- end
548
-
549
- if @relay_node_field
550
- field_defn.relay_node_field = @relay_node_field
551
- end
552
-
553
- if @relay_nodes_field
554
- field_defn.relay_nodes_field = @relay_nodes_field
555
- end
556
-
557
- if @legacy_edge_class
558
- field_defn.edge_class = @legacy_edge_class
559
- end
560
-
561
- field_defn.resolve = self.method(:resolve_field)
562
- field_defn.connection = connection?
563
- field_defn.connection_max_page_size = max_page_size
564
- field_defn.introspection = @introspection
565
- field_defn.complexity = @complexity
566
- field_defn.subscription_scope = @subscription_scope
567
- field_defn.ast_node = ast_node
568
-
569
- all_argument_definitions.each do |defn|
570
- arg_graphql = defn.deprecated_to_graphql
571
- field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
572
- end
561
+ # @return [Boolean] True if this field's {#default_page_size} should override the schema default.
562
+ def has_default_page_size?
563
+ !NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
564
+ end
573
565
 
574
- # Support a passed-in proc, one way or another
575
- @resolve_proc = if @resolve
576
- @resolve
577
- elsif @function
578
- @function
579
- elsif @field
580
- @field.resolve_proc
566
+ # @return [Integer, nil] Applied to connections if {#has_default_page_size?}
567
+ def default_page_size
568
+ if !NOT_CONFIGURED.equal?(@default_page_size)
569
+ @default_page_size
570
+ elsif @resolver_class && @resolver_class.has_default_page_size?
571
+ @resolver_class.default_page_size
572
+ else
573
+ nil
581
574
  end
582
-
583
- # Ok, `self` isn't a class, but this is for consistency with the classes
584
- field_defn.metadata[:type_class] = self
585
- field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
586
- field_defn
587
575
  end
588
576
 
589
577
  class MissingReturnTypeError < GraphQL::Error; end
590
578
  attr_writer :type
591
579
 
592
580
  def type
593
- @type ||= if @function
594
- Member::BuildType.parse_type(@function.type, null: false)
595
- elsif @field
596
- Member::BuildType.parse_type(@field.type, null: false)
597
- elsif @return_type_expr.nil?
598
- # Not enough info to determine type
599
- message = "Can't determine the return type for #{self.path}"
600
- if @resolver_class
601
- message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
581
+ if @resolver_class
582
+ return_type = @return_type_expr || @resolver_class.type_expr
583
+ if return_type.nil?
584
+ 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)"
602
585
  end
603
- raise MissingReturnTypeError, message
586
+ nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
587
+ Member::BuildType.parse_type(return_type, null: nullable)
604
588
  else
605
- Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
589
+ @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
606
590
  end
607
591
  rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
608
592
  # Let this propagate up
@@ -619,14 +603,6 @@ module GraphQL
619
603
  end
620
604
  end
621
605
 
622
- def accessible?(context)
623
- if @resolver_class
624
- @resolver_class.accessible?(context)
625
- else
626
- true
627
- end
628
- end
629
-
630
606
  def authorized?(object, args, context)
631
607
  if @resolver_class
632
608
  # The resolver _instance_ will check itself during `resolve()`
@@ -640,62 +616,33 @@ module GraphQL
640
616
  arg_values = args
641
617
  using_arg_values = false
642
618
  end
643
- # Faster than `.any?`
644
- arguments(context).each_value do |arg|
645
- arg_key = arg.keyword
646
- if arg_values.key?(arg_key)
647
- arg_value = arg_values[arg_key]
648
- if using_arg_values
649
- if arg_value.default_used?
650
- # pass -- no auth required for default used
651
- next
652
- else
653
- application_arg_value = arg_value.value
654
- if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
655
- application_arg_value.keyword_arguments
619
+ if args.size > 0
620
+ args = context.warden.arguments(self)
621
+ args.each do |arg|
622
+ arg_key = arg.keyword
623
+ if arg_values.key?(arg_key)
624
+ arg_value = arg_values[arg_key]
625
+ if using_arg_values
626
+ if arg_value.default_used?
627
+ # pass -- no auth required for default used
628
+ next
629
+ else
630
+ application_arg_value = arg_value.value
631
+ if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
632
+ application_arg_value.keyword_arguments
633
+ end
656
634
  end
635
+ else
636
+ application_arg_value = arg_value
657
637
  end
658
- else
659
- application_arg_value = arg_value
660
- end
661
638
 
662
- if !arg.authorized?(object, application_arg_value, context)
663
- return false
664
- end
665
- end
666
- end
667
- true
668
- end
669
- end
670
-
671
- # Implement {GraphQL::Field}'s resolve API.
672
- #
673
- # Eventually, we might hook up field instances to execution in another way. TBD.
674
- # @see #resolve for how the interpreter hooks up to it
675
- def resolve_field(obj, args, ctx)
676
- ctx.schema.after_lazy(obj) do |after_obj|
677
- # First, apply auth ...
678
- query_ctx = ctx.query.context
679
- # Some legacy fields can have `nil` here, not exactly sure why.
680
- # @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
681
- inner_obj = after_obj && after_obj.object
682
- ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
683
- if authorized?(inner_obj, ruby_args, query_ctx)
684
- # Then if it passed, resolve the field
685
- if @resolve_proc
686
- # Might be nil, still want to call the func in that case
687
- with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
688
- # Pass the GraphQL args here for compatibility:
689
- @resolve_proc.call(extended_obj, args, ctx)
639
+ if !arg.authorized?(object, application_arg_value, context)
640
+ return false
690
641
  end
691
- else
692
- public_send_field(after_obj, ruby_args, query_ctx)
693
642
  end
694
- else
695
- err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
696
- query_ctx.schema.unauthorized_field(err)
697
643
  end
698
644
  end
645
+ true
699
646
  end
700
647
  end
701
648
 
@@ -704,34 +651,110 @@ module GraphQL
704
651
  # @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
705
652
  # @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
706
653
  # @param ctx [GraphQL::Query::Context]
707
- def resolve(object, args, ctx)
708
- if @resolve_proc
709
- raise "Can't run resolve proc for #{path} when using GraphQL::Execution::Interpreter"
710
- end
711
- begin
712
- # Unwrap the GraphQL object to get the application object.
713
- application_object = object.object
654
+ def resolve(object, args, query_ctx)
655
+ # Unwrap the GraphQL object to get the application object.
656
+ application_object = object.object
657
+ method_receiver = nil
658
+ method_to_call = nil
659
+ method_args = nil
660
+
661
+ Schema::Validator.validate!(validators, application_object, query_ctx, args)
662
+
663
+ query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
664
+ if is_authorized
665
+ with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
666
+ method_args = ruby_kwargs
667
+ if @resolver_class
668
+ if obj.is_a?(GraphQL::Schema::Object)
669
+ obj = obj.object
670
+ end
671
+ obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
672
+ end
714
673
 
715
- Schema::Validator.validate!(validators, application_object, ctx, args)
674
+ inner_object = obj.object
716
675
 
717
- ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
718
- if is_authorized
719
- public_send_field(object, args, ctx)
720
- else
721
- raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
676
+ if !NOT_CONFIGURED.equal?(@hash_key)
677
+ hash_value = if inner_object.is_a?(Hash)
678
+ inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
679
+ elsif inner_object.respond_to?(:[])
680
+ inner_object[@hash_key]
681
+ else
682
+ nil
683
+ end
684
+ if hash_value == false
685
+ hash_value
686
+ else
687
+ hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
688
+ end
689
+ elsif obj.respond_to?(resolver_method)
690
+ method_to_call = resolver_method
691
+ method_receiver = obj
692
+ # Call the method with kwargs, if there are any
693
+ if ruby_kwargs.any?
694
+ obj.public_send(resolver_method, **ruby_kwargs)
695
+ else
696
+ obj.public_send(resolver_method)
697
+ end
698
+ elsif inner_object.is_a?(Hash)
699
+ if @dig_keys
700
+ inner_object.dig(*@dig_keys)
701
+ elsif inner_object.key?(@method_sym)
702
+ inner_object[@method_sym]
703
+ elsif inner_object.key?(@method_str)
704
+ inner_object[@method_str]
705
+ elsif @fallback_value != :not_given
706
+ @fallback_value
707
+ else
708
+ nil
709
+ end
710
+ elsif inner_object.respond_to?(@method_sym)
711
+ method_to_call = @method_sym
712
+ method_receiver = obj.object
713
+ if ruby_kwargs.any?
714
+ inner_object.public_send(@method_sym, **ruby_kwargs)
715
+ else
716
+ inner_object.public_send(@method_sym)
717
+ end
718
+ elsif @fallback_value != :not_given
719
+ @fallback_value
720
+ else
721
+ raise <<-ERR
722
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
723
+
724
+ - `#{obj.class}##{resolver_method}`, which did not exist
725
+ - `#{inner_object.class}##{@method_sym}`, which did not exist
726
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
727
+
728
+ To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
729
+ ERR
730
+ end
722
731
  end
732
+ else
733
+ raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
723
734
  end
724
- rescue GraphQL::UnauthorizedFieldError => err
725
- err.field ||= self
726
- ctx.schema.unauthorized_field(err)
727
- rescue GraphQL::UnauthorizedError => err
728
- ctx.schema.unauthorized_object(err)
729
- end
730
- rescue GraphQL::ExecutionError => err
731
- err
735
+ end
736
+ rescue GraphQL::UnauthorizedFieldError => err
737
+ err.field ||= self
738
+ begin
739
+ query_ctx.schema.unauthorized_field(err)
740
+ rescue GraphQL::ExecutionError => err
741
+ err
742
+ end
743
+ rescue GraphQL::UnauthorizedError => err
744
+ begin
745
+ query_ctx.schema.unauthorized_object(err)
746
+ rescue GraphQL::ExecutionError => err
747
+ err
748
+ end
749
+ rescue ArgumentError
750
+ if method_receiver && method_to_call
751
+ assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
752
+ end
753
+ # if the line above doesn't raise, re-raise
754
+ raise
732
755
  end
733
756
 
734
- # @param ctx [GraphQL::Query::Context::FieldResolutionContext]
757
+ # @param ctx [GraphQL::Query::Context]
735
758
  def fetch_extra(extra_name, ctx)
736
759
  if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
737
760
  self.public_send(extra_name)
@@ -744,127 +767,6 @@ module GraphQL
744
767
 
745
768
  private
746
769
 
747
- NO_ARGS = {}.freeze
748
-
749
- # Convert a GraphQL arguments instance into a Ruby-style hash.
750
- #
751
- # @param obj [GraphQL::Schema::Object] The object where this field is being resolved
752
- # @param graphql_args [GraphQL::Query::Arguments]
753
- # @param field_ctx [GraphQL::Query::Context::FieldResolutionContext]
754
- # @return [Hash<Symbol => Any>]
755
- def to_ruby_args(obj, graphql_args, field_ctx)
756
- if graphql_args.any? || @extras.any?
757
- # Splat the GraphQL::Arguments to Ruby keyword arguments
758
- ruby_kwargs = graphql_args.to_kwargs
759
- maybe_lazies = []
760
- # Apply any `prepare` methods. Not great code organization, can this go somewhere better?
761
- arguments(field_ctx).each do |name, arg_defn|
762
- ruby_kwargs_key = arg_defn.keyword
763
-
764
- if ruby_kwargs.key?(ruby_kwargs_key)
765
- loads = arg_defn.loads
766
- value = ruby_kwargs[ruby_kwargs_key]
767
- loaded_value = if loads && !arg_defn.from_resolver?
768
- if arg_defn.type.list?
769
- loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
770
- field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
771
- else
772
- load_application_object(arg_defn, loads, value, field_ctx.query.context)
773
- end
774
- elsif arg_defn.type.list? && value.is_a?(Array)
775
- field_ctx.schema.after_any_lazies(value, &:itself)
776
- else
777
- value
778
- end
779
-
780
- maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
781
- prepared_value = if arg_defn.prepare
782
- arg_defn.prepare_value(obj, loaded_value)
783
- else
784
- loaded_value
785
- end
786
-
787
- ruby_kwargs[ruby_kwargs_key] = prepared_value
788
- end
789
- end
790
- end
791
-
792
- @extras.each do |extra_arg|
793
- ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
794
- end
795
-
796
- field_ctx.schema.after_any_lazies(maybe_lazies) do
797
- ruby_kwargs
798
- end
799
- else
800
- NO_ARGS
801
- end
802
- end
803
-
804
- def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
805
- with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
806
- begin
807
- method_receiver = nil
808
- method_to_call = nil
809
- if @resolver_class
810
- if obj.is_a?(GraphQL::Schema::Object)
811
- obj = obj.object
812
- end
813
- obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
814
- end
815
-
816
- # Find a way to resolve this field, checking:
817
- #
818
- # - A method on the type instance;
819
- # - Hash keys, if the wrapped object is a hash;
820
- # - A method on the wrapped object;
821
- # - Or, raise not implemented.
822
- #
823
- if obj.respond_to?(@resolver_method)
824
- method_to_call = @resolver_method
825
- method_receiver = obj
826
- # Call the method with kwargs, if there are any
827
- if ruby_kwargs.any?
828
- obj.public_send(@resolver_method, **ruby_kwargs)
829
- else
830
- obj.public_send(@resolver_method)
831
- end
832
- elsif obj.object.is_a?(Hash)
833
- inner_object = obj.object
834
- if @dig_keys
835
- inner_object.dig(*@dig_keys)
836
- elsif inner_object.key?(@method_sym)
837
- inner_object[@method_sym]
838
- else
839
- inner_object[@method_str]
840
- end
841
- elsif obj.object.respond_to?(@method_sym)
842
- method_to_call = @method_sym
843
- method_receiver = obj.object
844
- if ruby_kwargs.any?
845
- obj.object.public_send(@method_sym, **ruby_kwargs)
846
- else
847
- obj.object.public_send(@method_sym)
848
- end
849
- else
850
- raise <<-ERR
851
- Failed to implement #{@owner.graphql_name}.#{@name}, tried:
852
-
853
- - `#{obj.class}##{@resolver_method}`, which did not exist
854
- - `#{obj.object.class}##{@method_sym}`, which did not exist
855
- - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
856
-
857
- To implement this field, define one of the methods above (and check for typos)
858
- ERR
859
- end
860
- rescue ArgumentError
861
- assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
862
- # if the line above doesn't raise, re-raise
863
- raise
864
- end
865
- end
866
- end
867
-
868
770
  def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
869
771
  method_defn = receiver.method(method_name)
870
772
  unsatisfied_ruby_kwargs = ruby_kwargs.dup
@@ -895,7 +797,7 @@ module GraphQL
895
797
 
896
798
  if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
897
799
  raise FieldImplementationFailed.new, <<-ERR
898
- Failed to call #{method_name} on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
800
+ Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
899
801
 
900
802
  #{ unsatisfied_ruby_kwargs
901
803
  .map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }