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