graphql 1.13.12 → 2.0.21

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