graphql 1.13.24 → 2.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +50 -1
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  9. data/lib/generators/graphql/relay.rb +21 -18
  10. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  11. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  12. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  13. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  14. data/lib/generators/graphql/templates/base_field.erb +2 -0
  15. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  16. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  17. data/lib/generators/graphql/templates/base_object.erb +2 -0
  18. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  19. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  20. data/lib/generators/graphql/templates/base_union.erb +2 -0
  21. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  22. data/lib/generators/graphql/templates/loader.erb +2 -0
  23. data/lib/generators/graphql/templates/mutation.erb +2 -0
  24. data/lib/generators/graphql/templates/node_type.erb +2 -0
  25. data/lib/generators/graphql/templates/query_type.erb +2 -0
  26. data/lib/generators/graphql/templates/schema.erb +8 -0
  27. data/lib/generators/graphql/type_generator.rb +1 -1
  28. data/lib/graphql/analysis/analyzer.rb +90 -0
  29. data/lib/graphql/analysis/field_usage.rb +65 -28
  30. data/lib/graphql/analysis/max_query_complexity.rb +11 -17
  31. data/lib/graphql/analysis/max_query_depth.rb +13 -19
  32. data/lib/graphql/analysis/query_complexity.rb +236 -61
  33. data/lib/graphql/analysis/query_depth.rb +38 -23
  34. data/lib/graphql/analysis/visitor.rb +280 -0
  35. data/lib/graphql/analysis.rb +93 -6
  36. data/lib/graphql/autoload.rb +38 -0
  37. data/lib/graphql/backtrace/table.rb +118 -73
  38. data/lib/graphql/backtrace.rb +2 -25
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/current.rb +57 -0
  41. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  42. data/lib/graphql/dashboard/installable.rb +22 -0
  43. data/lib/graphql/dashboard/limiters.rb +93 -0
  44. data/lib/graphql/dashboard/operation_store.rb +199 -0
  45. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  46. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  47. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  48. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  49. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  50. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  51. data/lib/graphql/dashboard/statics/icon.png +0 -0
  52. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  53. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  54. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  65. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  66. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  67. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  68. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  69. data/lib/graphql/dashboard.rb +158 -0
  70. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  71. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  72. data/lib/graphql/dataloader/async_dataloader.rb +101 -0
  73. data/lib/graphql/dataloader/null_dataloader.rb +11 -2
  74. data/lib/graphql/dataloader/request.rb +5 -0
  75. data/lib/graphql/dataloader/source.rb +103 -47
  76. data/lib/graphql/dataloader.rb +174 -148
  77. data/lib/graphql/dig.rb +3 -2
  78. data/lib/graphql/duration_encoding_error.rb +16 -0
  79. data/lib/graphql/execution/errors.rb +12 -82
  80. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  81. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  82. data/lib/graphql/execution/interpreter/arguments_cache.rb +30 -35
  83. data/lib/graphql/execution/interpreter/resolve.rb +32 -2
  84. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +215 -0
  85. data/lib/graphql/execution/interpreter/runtime.rb +525 -502
  86. data/lib/graphql/execution/interpreter.rb +127 -81
  87. data/lib/graphql/execution/lazy.rb +7 -21
  88. data/lib/graphql/execution/lookahead.rb +133 -55
  89. data/lib/graphql/execution/multiplex.rb +6 -176
  90. data/lib/graphql/execution.rb +11 -4
  91. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  92. data/lib/graphql/introspection/directive_type.rb +1 -1
  93. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  94. data/lib/graphql/introspection/entry_points.rb +10 -17
  95. data/lib/graphql/introspection/field_type.rb +1 -1
  96. data/lib/graphql/introspection/schema_type.rb +8 -11
  97. data/lib/graphql/introspection/type_type.rb +13 -6
  98. data/lib/graphql/introspection.rb +4 -3
  99. data/lib/graphql/invalid_name_error.rb +1 -1
  100. data/lib/graphql/invalid_null_error.rb +20 -17
  101. data/lib/graphql/language/block_string.rb +34 -18
  102. data/lib/graphql/language/cache.rb +13 -0
  103. data/lib/graphql/language/comment.rb +18 -0
  104. data/lib/graphql/language/definition_slice.rb +1 -1
  105. data/lib/graphql/language/document_from_schema_definition.rb +114 -80
  106. data/lib/graphql/language/lexer.rb +375 -1489
  107. data/lib/graphql/language/nodes.rb +189 -104
  108. data/lib/graphql/language/parser.rb +807 -1941
  109. data/lib/graphql/language/printer.rb +366 -163
  110. data/lib/graphql/language/sanitized_printer.rb +21 -23
  111. data/lib/graphql/language/static_visitor.rb +171 -0
  112. data/lib/graphql/language/visitor.rb +189 -138
  113. data/lib/graphql/language.rb +62 -1
  114. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  115. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  116. data/lib/graphql/pagination/array_connection.rb +8 -6
  117. data/lib/graphql/pagination/connection.rb +61 -7
  118. data/lib/graphql/pagination/connections.rb +3 -28
  119. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  120. data/lib/graphql/pagination/relation_connection.rb +2 -0
  121. data/lib/graphql/query/context/scoped_context.rb +101 -0
  122. data/lib/graphql/query/context.rb +131 -225
  123. data/lib/graphql/query/input_validation_result.rb +1 -1
  124. data/lib/graphql/query/null_context.rb +11 -33
  125. data/lib/graphql/query/partial.rb +179 -0
  126. data/lib/graphql/query/validation_pipeline.rb +14 -37
  127. data/lib/graphql/query/variable_validation_error.rb +1 -1
  128. data/lib/graphql/query/variables.rb +6 -19
  129. data/lib/graphql/query.rb +162 -98
  130. data/lib/graphql/railtie.rb +15 -109
  131. data/lib/graphql/rake_task/validate.rb +1 -1
  132. data/lib/graphql/rake_task.rb +30 -11
  133. data/lib/graphql/relay/range_add.rb +9 -20
  134. data/lib/graphql/relay.rb +0 -15
  135. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  136. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  137. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  138. data/lib/graphql/rubocop.rb +2 -0
  139. data/lib/graphql/schema/addition.rb +70 -33
  140. data/lib/graphql/schema/always_visible.rb +15 -0
  141. data/lib/graphql/schema/argument.rb +104 -59
  142. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  143. data/lib/graphql/schema/build_from_definition.rb +154 -74
  144. data/lib/graphql/schema/directive/flagged.rb +4 -2
  145. data/lib/graphql/schema/directive/one_of.rb +24 -0
  146. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  147. data/lib/graphql/schema/directive/transform.rb +1 -1
  148. data/lib/graphql/schema/directive.rb +47 -24
  149. data/lib/graphql/schema/enum.rb +137 -65
  150. data/lib/graphql/schema/enum_value.rb +11 -26
  151. data/lib/graphql/schema/field/connection_extension.rb +6 -16
  152. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  153. data/lib/graphql/schema/field.rb +399 -404
  154. data/lib/graphql/schema/field_extension.rb +2 -5
  155. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +144 -99
  158. data/lib/graphql/schema/interface.rb +34 -51
  159. data/lib/graphql/schema/introspection_system.rb +12 -26
  160. data/lib/graphql/schema/late_bound_type.rb +12 -2
  161. data/lib/graphql/schema/list.rb +3 -9
  162. data/lib/graphql/schema/loader.rb +4 -6
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
  164. data/lib/graphql/schema/member/build_type.rb +15 -9
  165. data/lib/graphql/schema/member/has_arguments.rb +192 -96
  166. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  167. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  168. data/lib/graphql/schema/member/has_deprecation_reason.rb +18 -4
  169. data/lib/graphql/schema/member/has_directives.rb +81 -61
  170. data/lib/graphql/schema/member/has_fields.rb +119 -39
  171. data/lib/graphql/schema/member/has_interfaces.rb +66 -23
  172. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  173. data/lib/graphql/schema/member/has_validators.rb +32 -6
  174. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  175. data/lib/graphql/schema/member/scoped.rb +19 -0
  176. data/lib/graphql/schema/member/type_system_helpers.rb +32 -2
  177. data/lib/graphql/schema/member/validates_input.rb +4 -4
  178. data/lib/graphql/schema/member.rb +1 -6
  179. data/lib/graphql/schema/mutation.rb +7 -9
  180. data/lib/graphql/schema/non_null.rb +1 -7
  181. data/lib/graphql/schema/object.rb +42 -49
  182. data/lib/graphql/schema/printer.rb +12 -8
  183. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  184. data/lib/graphql/schema/relay_classic_mutation.rb +12 -124
  185. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  186. data/lib/graphql/schema/resolver.rb +96 -81
  187. data/lib/graphql/schema/scalar.rb +10 -30
  188. data/lib/graphql/schema/subscription.rb +60 -14
  189. data/lib/graphql/schema/timeout.rb +44 -31
  190. data/lib/graphql/schema/type_expression.rb +2 -2
  191. data/lib/graphql/schema/type_membership.rb +3 -0
  192. data/lib/graphql/schema/union.rb +12 -19
  193. data/lib/graphql/schema/unique_within_type.rb +1 -1
  194. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  195. data/lib/graphql/schema/validator/required_validator.rb +60 -10
  196. data/lib/graphql/schema/validator.rb +5 -3
  197. data/lib/graphql/schema/visibility/migration.rb +188 -0
  198. data/lib/graphql/schema/visibility/profile.rb +445 -0
  199. data/lib/graphql/schema/visibility/visit.rb +190 -0
  200. data/lib/graphql/schema/visibility.rb +311 -0
  201. data/lib/graphql/schema/warden.rb +318 -94
  202. data/lib/graphql/schema/wrapper.rb +0 -5
  203. data/lib/graphql/schema.rb +1148 -1085
  204. data/lib/graphql/static_validation/all_rules.rb +4 -3
  205. data/lib/graphql/static_validation/base_visitor.rb +11 -27
  206. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  207. data/lib/graphql/static_validation/error.rb +2 -2
  208. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  209. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  210. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  211. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  212. data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
  213. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -12
  214. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  215. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +48 -6
  216. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -27
  217. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  218. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  219. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  220. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  221. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  222. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  223. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  224. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  225. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  226. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  227. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  228. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  229. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  230. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +19 -9
  231. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  232. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  233. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  234. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  235. data/lib/graphql/static_validation/validation_context.rb +21 -5
  236. data/lib/graphql/static_validation/validator.rb +12 -26
  237. data/lib/graphql/static_validation.rb +0 -3
  238. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -6
  239. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  240. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
  241. data/lib/graphql/subscriptions/event.rb +24 -12
  242. data/lib/graphql/subscriptions/serialize.rb +3 -1
  243. data/lib/graphql/subscriptions.rb +48 -32
  244. data/lib/graphql/testing/helpers.rb +158 -0
  245. data/lib/graphql/testing.rb +2 -0
  246. data/lib/graphql/tracing/active_support_notifications_trace.rb +27 -0
  247. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  248. data/lib/graphql/tracing/appoptics_trace.rb +259 -0
  249. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  250. data/lib/graphql/tracing/appsignal_trace.rb +54 -0
  251. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  252. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  253. data/lib/graphql/tracing/data_dog_trace.rb +71 -0
  254. data/lib/graphql/tracing/data_dog_tracing.rb +3 -0
  255. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  256. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  257. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  258. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
  259. data/lib/graphql/tracing/legacy_trace.rb +12 -0
  260. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  261. data/lib/graphql/tracing/new_relic_trace.rb +68 -0
  262. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  263. data/lib/graphql/tracing/notifications_trace.rb +195 -0
  264. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  265. data/lib/graphql/tracing/null_trace.rb +9 -0
  266. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  267. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  268. data/lib/graphql/tracing/perfetto_trace.rb +734 -0
  269. data/lib/graphql/tracing/platform_trace.rb +123 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +28 -41
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
  272. data/lib/graphql/tracing/prometheus_trace.rb +93 -0
  273. data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
  274. data/lib/graphql/tracing/scout_trace.rb +49 -0
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +80 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +48 -0
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +186 -0
  280. data/lib/graphql/tracing.rb +32 -52
  281. data/lib/graphql/type_kinds.rb +8 -4
  282. data/lib/graphql/types/iso_8601_date.rb +4 -1
  283. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  284. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  285. data/lib/graphql/types/relay/base_connection.rb +16 -6
  286. data/lib/graphql/types/relay/connection_behaviors.rb +65 -23
  287. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  288. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  289. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  290. data/lib/graphql/types/relay.rb +0 -3
  291. data/lib/graphql/types/string.rb +1 -1
  292. data/lib/graphql/types.rb +18 -10
  293. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  294. data/lib/graphql/version.rb +1 -1
  295. data/lib/graphql.rb +76 -123
  296. data/readme.md +13 -3
  297. metadata +225 -142
  298. data/lib/graphql/analysis/analyze_query.rb +0 -98
  299. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  300. data/lib/graphql/analysis/ast/field_usage.rb +0 -55
  301. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
  302. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  303. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  304. data/lib/graphql/analysis/ast/query_depth.rb +0 -56
  305. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  306. data/lib/graphql/analysis/ast.rb +0 -91
  307. data/lib/graphql/analysis/reducer_state.rb +0 -48
  308. data/lib/graphql/argument.rb +0 -131
  309. data/lib/graphql/authorization.rb +0 -82
  310. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  311. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  312. data/lib/graphql/backtrace/tracer.rb +0 -81
  313. data/lib/graphql/backwards_compatibility.rb +0 -61
  314. data/lib/graphql/base_type.rb +0 -232
  315. data/lib/graphql/boolean_type.rb +0 -2
  316. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  317. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  318. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  319. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  320. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  321. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  322. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  323. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  324. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  325. data/lib/graphql/compatibility.rb +0 -5
  326. data/lib/graphql/define/assign_argument.rb +0 -12
  327. data/lib/graphql/define/assign_connection.rb +0 -13
  328. data/lib/graphql/define/assign_enum_value.rb +0 -18
  329. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  330. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  331. data/lib/graphql/define/assign_object_field.rb +0 -42
  332. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  333. data/lib/graphql/define/instance_definable.rb +0 -255
  334. data/lib/graphql/define/no_definition_error.rb +0 -7
  335. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  336. data/lib/graphql/define/type_definer.rb +0 -31
  337. data/lib/graphql/define.rb +0 -31
  338. data/lib/graphql/deprecated_dsl.rb +0 -55
  339. data/lib/graphql/deprecation.rb +0 -9
  340. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  341. data/lib/graphql/directive/include_directive.rb +0 -2
  342. data/lib/graphql/directive/skip_directive.rb +0 -2
  343. data/lib/graphql/directive.rb +0 -107
  344. data/lib/graphql/enum_type.rb +0 -133
  345. data/lib/graphql/execution/execute.rb +0 -333
  346. data/lib/graphql/execution/flatten.rb +0 -40
  347. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  348. data/lib/graphql/execution/typecast.rb +0 -50
  349. data/lib/graphql/field/resolve.rb +0 -59
  350. data/lib/graphql/field.rb +0 -226
  351. data/lib/graphql/filter.rb +0 -53
  352. data/lib/graphql/float_type.rb +0 -2
  353. data/lib/graphql/function.rb +0 -128
  354. data/lib/graphql/id_type.rb +0 -2
  355. data/lib/graphql/input_object_type.rb +0 -138
  356. data/lib/graphql/int_type.rb +0 -2
  357. data/lib/graphql/interface_type.rb +0 -72
  358. data/lib/graphql/internal_representation/document.rb +0 -27
  359. data/lib/graphql/internal_representation/node.rb +0 -206
  360. data/lib/graphql/internal_representation/print.rb +0 -51
  361. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  362. data/lib/graphql/internal_representation/scope.rb +0 -88
  363. data/lib/graphql/internal_representation/visit.rb +0 -36
  364. data/lib/graphql/internal_representation.rb +0 -7
  365. data/lib/graphql/language/lexer.rl +0 -260
  366. data/lib/graphql/language/parser.y +0 -550
  367. data/lib/graphql/language/token.rb +0 -34
  368. data/lib/graphql/list_type.rb +0 -80
  369. data/lib/graphql/non_null_type.rb +0 -71
  370. data/lib/graphql/object_type.rb +0 -130
  371. data/lib/graphql/query/arguments.rb +0 -189
  372. data/lib/graphql/query/arguments_cache.rb +0 -24
  373. data/lib/graphql/query/executor.rb +0 -52
  374. data/lib/graphql/query/literal_input.rb +0 -136
  375. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  376. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  377. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  378. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  379. data/lib/graphql/query/serial_execution.rb +0 -40
  380. data/lib/graphql/relay/array_connection.rb +0 -83
  381. data/lib/graphql/relay/base_connection.rb +0 -189
  382. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  383. data/lib/graphql/relay/connection_resolve.rb +0 -43
  384. data/lib/graphql/relay/connection_type.rb +0 -54
  385. data/lib/graphql/relay/edge.rb +0 -27
  386. data/lib/graphql/relay/edge_type.rb +0 -19
  387. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  388. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  389. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  390. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  391. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  392. data/lib/graphql/relay/mutation/result.rb +0 -38
  393. data/lib/graphql/relay/mutation.rb +0 -106
  394. data/lib/graphql/relay/node.rb +0 -39
  395. data/lib/graphql/relay/page_info.rb +0 -7
  396. data/lib/graphql/relay/relation_connection.rb +0 -188
  397. data/lib/graphql/relay/type_extensions.rb +0 -32
  398. data/lib/graphql/scalar_type.rb +0 -91
  399. data/lib/graphql/schema/base_64_bp.rb +0 -26
  400. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  401. data/lib/graphql/schema/default_parse_error.rb +0 -10
  402. data/lib/graphql/schema/default_type_error.rb +0 -17
  403. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  404. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  405. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  406. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  407. data/lib/graphql/schema/middleware_chain.rb +0 -82
  408. data/lib/graphql/schema/null_mask.rb +0 -11
  409. data/lib/graphql/schema/possible_types.rb +0 -44
  410. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  411. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  412. data/lib/graphql/schema/traversal.rb +0 -228
  413. data/lib/graphql/schema/validation.rb +0 -313
  414. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  415. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  416. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  417. data/lib/graphql/static_validation/type_stack.rb +0 -216
  418. data/lib/graphql/string_type.rb +0 -2
  419. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  420. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  421. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  422. data/lib/graphql/types/relay/default_relay.rb +0 -31
  423. data/lib/graphql/types/relay/node_field.rb +0 -24
  424. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  425. data/lib/graphql/union_type.rb +0 -115
  426. data/lib/graphql/upgrader/member.rb +0 -937
  427. 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,43 @@ 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
43
+
44
+ # @return [String, nil]
45
+ def deprecation_reason
46
+ super || @resolver_class&.deprecation_reason
47
+ end
48
+
49
+ def directives
50
+ if @resolver_class && !(r_dirs = @resolver_class.directives).empty?
51
+ if !(own_dirs = super).empty?
52
+ new_dirs = own_dirs.dup
53
+ r_dirs.each do |r_dir|
54
+ if r_dir.class.repeatable? ||
55
+ ( (r_dir_name = r_dir.graphql_name) &&
56
+ (!new_dirs.any? { |d| d.graphql_name == r_dir_name })
57
+ )
58
+ new_dirs << r_dir
59
+ end
60
+ end
61
+ new_dirs
62
+ else
63
+ r_dirs
64
+ end
65
+ else
66
+ super
67
+ end
68
+ end
35
69
 
36
70
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
37
71
  attr_accessor :owner
@@ -61,7 +95,7 @@ module GraphQL
61
95
  end
62
96
 
63
97
  def inspect
64
- "#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
98
+ "#<#{self.class} #{path}#{!all_argument_definitions.empty? ? "(...)" : ""}: #{type.to_type_signature}>"
65
99
  end
66
100
 
67
101
  alias :mutation :resolver
@@ -70,7 +104,10 @@ module GraphQL
70
104
  attr_reader :trace
71
105
 
72
106
  # @return [String, nil]
73
- attr_accessor :subscription_scope
107
+ def subscription_scope
108
+ @subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
109
+ end
110
+ attr_writer :subscription_scope
74
111
 
75
112
  # Create a field instance from a list of arguments, keyword arguments, and a block.
76
113
  #
@@ -81,34 +118,23 @@ module GraphQL
81
118
  # @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
82
119
  # @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
83
120
  # @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
84
- # @return [GraphQL::Schema:Field] an instance of `self
121
+ # @return [GraphQL::Schema:Field] an instance of `self`
85
122
  # @see {.initialize} for other options
86
- 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)
123
+ def self.from_options(name = nil, type = nil, desc = nil, comment: nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
124
+ if (resolver_class = resolver || mutation || subscription)
100
125
  # Add a reference to that parent class
101
- kwargs[:resolver_class] = parent_config
126
+ kwargs[:resolver_class] = resolver_class
102
127
  end
103
128
 
104
129
  if name
105
130
  kwargs[:name] = name
106
131
  end
107
132
 
133
+ if comment
134
+ kwargs[:comment] = comment
135
+ end
136
+
108
137
  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
138
  if desc
113
139
  if kwargs[:description]
114
140
  raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
@@ -116,8 +142,8 @@ module GraphQL
116
142
 
117
143
  kwargs[:description] = desc
118
144
  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
145
+ elsif (resolver || mutation) && type.is_a?(String)
146
+ # The return type should be copied from the resolver, and the second positional argument is the description
121
147
  kwargs[:description] = type
122
148
  else
123
149
  kwargs[:type] = type
@@ -134,15 +160,20 @@ module GraphQL
134
160
  def connection?
135
161
  if @connection.nil?
136
162
  # 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
163
+ return_type_name = if @return_type_expr
140
164
  Member::BuildType.to_type_name(@return_type_expr)
141
- else
165
+ elsif @resolver_class && @resolver_class.type
166
+ Member::BuildType.to_type_name(@resolver_class.type)
167
+ elsif type
142
168
  # As a last ditch, try to force loading the return type:
143
169
  type.unwrap.name
144
170
  end
145
- @connection = return_type_name.end_with?("Connection")
171
+ if return_type_name
172
+ @connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
173
+ else
174
+ # TODO set this when type is set by method
175
+ false # not loaded yet?
176
+ end
146
177
  else
147
178
  @connection
148
179
  end
@@ -153,8 +184,18 @@ module GraphQL
153
184
  if !@scope.nil?
154
185
  # The default was overridden
155
186
  @scope
187
+ elsif @return_type_expr
188
+ # Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
189
+ @return_type_expr.is_a?(Array) ||
190
+ (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
191
+ connection?
192
+ elsif @resolver_class
193
+ resolver_type = @resolver_class.type_expr
194
+ resolver_type.is_a?(Array) ||
195
+ (resolver_type.is_a?(String) && resolver_type.include?("[")) ||
196
+ connection?
156
197
  else
157
- @return_type_expr && (@return_type_expr.is_a?(Array) || (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) || connection?)
198
+ false
158
199
  end
159
200
  end
160
201
 
@@ -187,8 +228,9 @@ module GraphQL
187
228
  # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
188
229
  # @param type [Class, GraphQL::BaseType, Array] The return type of this field
189
230
  # @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`
231
+ # @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
191
232
  # @param description [String] Field description
233
+ # @param comment [String] Field comment
192
234
  # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
193
235
  # @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
194
236
  # @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
@@ -197,10 +239,8 @@ module GraphQL
197
239
  # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
198
240
  # @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
199
241
  # @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
242
+ # @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
243
  # @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
244
  # @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
205
245
  # @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
206
246
  # @param camelize [Boolean] If true, the field name will be camelized when building the schema
@@ -214,19 +254,16 @@ module GraphQL
214
254
  # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
215
255
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
216
256
  # @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)
257
+ # @param fallback_value [Object] A fallback value if the method is not defined
258
+ def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, comment: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
219
259
  if name.nil?
220
260
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
221
261
  end
222
- if !(field || function || resolver_class)
223
- if type.nil?
224
- raise ArgumentError, "missing second `type` argument or keyword `type:`"
262
+ if !(resolver_class)
263
+ if type.nil? && !block_given?
264
+ raise ArgumentError, "missing second `type` argument, keyword `type:`, or a block containing `type(...)`"
225
265
  end
226
266
  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
267
  @original_name = name
231
268
  name_s = -name.to_s
232
269
 
@@ -234,13 +271,9 @@ module GraphQL
234
271
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
235
272
  NameValidator.validate!(@name)
236
273
  @description = description
237
- if field.is_a?(GraphQL::Schema::Field)
238
- raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
239
- else
240
- @field = field
241
- end
242
- @function = function
243
- @resolve = resolve
274
+ @comment = comment
275
+ @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
276
+
244
277
  self.deprecation_reason = deprecation_reason
245
278
 
246
279
  if method && hash_key && dig
@@ -257,24 +290,32 @@ module GraphQL
257
290
  end
258
291
  end
259
292
 
260
- # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
261
293
  method_name = method || hash_key || name_s
262
294
  @dig_keys = dig
263
295
  if hash_key
264
296
  @hash_key = hash_key
297
+ @hash_key_str = hash_key.to_s
298
+ else
299
+ @hash_key = NOT_CONFIGURED
300
+ @hash_key_str = NOT_CONFIGURED
265
301
  end
266
302
 
267
- resolver_method ||= name_s.to_sym
268
-
269
303
  @method_str = -method_name.to_s
270
304
  @method_sym = method_name.to_sym
271
- @resolver_method = resolver_method
305
+ @resolver_method = (resolver_method || name_s).to_sym
272
306
  @complexity = complexity
307
+ @dynamic_introspection = dynamic_introspection
273
308
  @return_type_expr = type
274
- @return_type_null = null
309
+ @return_type_null = if !null.nil?
310
+ null
311
+ elsif resolver_class
312
+ nil
313
+ else
314
+ true
315
+ end
275
316
  @connection = connection
276
- @has_max_page_size = max_page_size != :not_given
277
- @max_page_size = max_page_size == :not_given ? nil : max_page_size
317
+ @max_page_size = max_page_size
318
+ @default_page_size = default_page_size
278
319
  @introspection = introspection
279
320
  @extras = extras
280
321
  @broadcastable = broadcastable
@@ -285,7 +326,8 @@ module GraphQL
285
326
  @relay_nodes_field = relay_nodes_field
286
327
  @ast_node = ast_node
287
328
  @method_conflict_warning = method_conflict_warning
288
- @legacy_edge_class = legacy_edge_class
329
+ @fallback_value = fallback_value
330
+ @definition_block = definition_block
289
331
 
290
332
  arguments.each do |name, arg|
291
333
  case arg
@@ -305,48 +347,64 @@ module GraphQL
305
347
 
306
348
  @extensions = EMPTY_ARRAY
307
349
  @call_after_define = false
308
- # This should run before connection extension,
309
- # but should it run after the definition block?
310
- if scoped?
311
- self.extension(ScopeExtension)
312
- end
313
-
314
- # The problem with putting this after the definition_block
315
- # is that it would override arguments
316
- if connection? && connection_extension
317
- self.extension(connection_extension)
318
- end
319
-
350
+ set_pagination_extensions(connection_extension: connection_extension)
320
351
  # Do this last so we have as much context as possible when initializing them:
321
- if extensions.any?
352
+ if !extensions.empty?
322
353
  self.extensions(extensions)
323
354
  end
324
355
 
325
- if directives.any?
356
+ if resolver_class && !resolver_class.extensions.empty?
357
+ self.extensions(resolver_class.extensions)
358
+ end
359
+
360
+ if !directives.empty?
326
361
  directives.each do |(dir_class, options)|
327
362
  self.directive(dir_class, **options)
328
363
  end
329
364
  end
330
365
 
331
- self.validates(validates)
366
+ if !validates.empty?
367
+ self.validates(validates)
368
+ end
332
369
 
333
- if definition_block
334
- if definition_block.arity == 1
335
- yield self
370
+ if @definition_block.nil?
371
+ self.extensions.each(&:after_define_apply)
372
+ @call_after_define = true
373
+ end
374
+ end
375
+
376
+ # Calls the definition block, if one was given.
377
+ # This is deferred so that references to the return type
378
+ # can be lazily evaluated, reducing Rails boot time.
379
+ # @return [self]
380
+ # @api private
381
+ def ensure_loaded
382
+ if @definition_block
383
+ if @definition_block.arity == 1
384
+ @definition_block.call(self)
336
385
  else
337
- instance_eval(&definition_block)
386
+ instance_exec(self, &@definition_block)
338
387
  end
388
+ self.extensions.each(&:after_define_apply)
389
+ @call_after_define = true
390
+ @definition_block = nil
339
391
  end
340
-
341
- self.extensions.each(&:after_define_apply)
342
- @call_after_define = true
392
+ self
343
393
  end
344
394
 
395
+ attr_accessor :dynamic_introspection
396
+
345
397
  # If true, subscription updates with this field can be shared between viewers
346
398
  # @return [Boolean, nil]
347
399
  # @see GraphQL::Subscriptions::BroadcastAnalyzer
348
400
  def broadcastable?
349
- @broadcastable
401
+ if !NOT_CONFIGURED.equal?(@broadcastable)
402
+ @broadcastable
403
+ elsif @resolver_class
404
+ @resolver_class.broadcastable?
405
+ else
406
+ nil
407
+ end
350
408
  end
351
409
 
352
410
  # @param text [String]
@@ -354,8 +412,26 @@ module GraphQL
354
412
  def description(text = nil)
355
413
  if text
356
414
  @description = text
357
- else
415
+ elsif !NOT_CONFIGURED.equal?(@description)
358
416
  @description
417
+ elsif @resolver_class
418
+ @resolver_class.description
419
+ else
420
+ nil
421
+ end
422
+ end
423
+
424
+ # @param text [String]
425
+ # @return [String, nil]
426
+ def comment(text = nil)
427
+ if text
428
+ @comment = text
429
+ elsif !NOT_CONFIGURED.equal?(@comment)
430
+ @comment
431
+ elsif @resolver_class
432
+ @resolver_class.comment
433
+ else
434
+ nil
359
435
  end
360
436
  end
361
437
 
@@ -379,7 +455,7 @@ module GraphQL
379
455
  new_extensions.each do |extension_config|
380
456
  if extension_config.is_a?(Hash)
381
457
  extension_class, options = *extension_config.to_a[0]
382
- self.extension(extension_class, options)
458
+ self.extension(extension_class, **options)
383
459
  else
384
460
  self.extension(extension_config)
385
461
  end
@@ -399,7 +475,7 @@ module GraphQL
399
475
  # @param extension_class [Class] subclass of {Schema::FieldExtension}
400
476
  # @param options [Hash] if provided, given as `options:` when initializing `extension`.
401
477
  # @return [void]
402
- def extension(extension_class, options = nil)
478
+ def extension(extension_class, **options)
403
479
  extension_inst = extension_class.new(field: self, options: options)
404
480
  if @extensions.frozen?
405
481
  @extensions = @extensions.dup
@@ -419,7 +495,12 @@ module GraphQL
419
495
  def extras(new_extras = nil)
420
496
  if new_extras.nil?
421
497
  # Read the value
422
- @extras
498
+ field_extras = @extras
499
+ if @resolver_class && !@resolver_class.extras.empty?
500
+ field_extras + @resolver_class.extras
501
+ else
502
+ field_extras
503
+ end
423
504
  else
424
505
  if @extras.frozen?
425
506
  @extras = @extras.dup
@@ -444,53 +525,38 @@ module GraphQL
444
525
  if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
445
526
  max_possible_page_size = arguments[:last]
446
527
  end
528
+ elsif arguments.is_a?(GraphQL::ExecutionError) || arguments.is_a?(GraphQL::UnauthorizedError)
529
+ raise arguments
447
530
  end
448
531
 
449
532
  if max_possible_page_size.nil?
450
- max_possible_page_size = max_page_size || query.schema.default_max_page_size
533
+ max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
451
534
  end
452
535
 
453
536
  if max_possible_page_size.nil?
454
- raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
537
+ raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
455
538
  else
456
539
  metadata_complexity = 0
457
540
  lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
458
541
 
459
- if (page_info_lookahead = lookahead.selection(:page_info)).selected?
460
- metadata_complexity += 1 # pageInfo
461
- metadata_complexity += page_info_lookahead.selections.size # subfields
462
- end
463
-
464
- if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
465
- metadata_complexity += 1
542
+ lookahead.selections.each do |next_lookahead|
543
+ # this includes `pageInfo`, `nodes` and `edges` and any custom fields
544
+ # TODO this doesn't support procs yet -- unlikely to need it.
545
+ metadata_complexity += next_lookahead.field.complexity
546
+ if next_lookahead.name != :nodes && next_lookahead.name != :edges
547
+ # subfields, eg, for pageInfo -- assumes no subselections
548
+ metadata_complexity += next_lookahead.selections.size
549
+ end
466
550
  end
467
551
 
468
- nodes_edges_complexity = 0
469
- nodes_edges_complexity += 1 if lookahead.selects?(:edges)
470
- nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
471
-
472
552
  # Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
473
- items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
474
- # Add 1 for _this_ field
475
- 1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
553
+ items_complexity = child_complexity - metadata_complexity
554
+ subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
555
+ # Apply this field's own complexity
556
+ apply_own_complexity_to(subfields_complexity, query, nodes)
476
557
  end
477
558
  else
478
- defined_complexity = complexity
479
- case defined_complexity
480
- when Proc
481
- arguments = query.arguments_for(nodes.first, self)
482
- if arguments.is_a?(GraphQL::ExecutionError)
483
- return child_complexity
484
- elsif arguments.respond_to?(:keyword_arguments)
485
- arguments = arguments.keyword_arguments
486
- end
487
-
488
- defined_complexity.call(query.context, arguments, child_complexity)
489
- when Numeric
490
- defined_complexity + child_complexity
491
- else
492
- raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
493
- end
559
+ apply_own_complexity_to(child_complexity, query, nodes)
494
560
  end
495
561
  end
496
562
 
@@ -508,7 +574,11 @@ module GraphQL
508
574
  when Numeric
509
575
  @complexity = new_complexity
510
576
  when nil
511
- @complexity
577
+ if @resolver_class
578
+ @complexity || @resolver_class.complexity || 1
579
+ else
580
+ @complexity || 1
581
+ end
512
582
  else
513
583
  raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
514
584
  end
@@ -516,105 +586,70 @@ module GraphQL
516
586
 
517
587
  # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
518
588
  def has_max_page_size?
519
- @has_max_page_size
589
+ !NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
520
590
  end
521
591
 
522
592
  # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
523
- attr_reader :max_page_size
524
-
525
- prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
526
-
527
- # @return [GraphQL::Field]
528
- def to_graphql
529
- field_defn = if @field
530
- @field.dup
531
- elsif @function
532
- GraphQL::Function.build_field(@function)
593
+ def max_page_size
594
+ if !NOT_CONFIGURED.equal?(@max_page_size)
595
+ @max_page_size
596
+ elsif @resolver_class && @resolver_class.has_max_page_size?
597
+ @resolver_class.max_page_size
533
598
  else
534
- GraphQL::Field.new
535
- end
536
-
537
- field_defn.name = @name
538
- if @return_type_expr
539
- field_defn.type = -> { type }
599
+ nil
540
600
  end
601
+ end
541
602
 
542
- if @description
543
- field_defn.description = @description
544
- end
545
-
546
- if self.deprecation_reason
547
- field_defn.deprecation_reason = self.deprecation_reason
548
- end
549
-
550
- if @resolver_class
551
- if @resolver_class < GraphQL::Schema::Mutation
552
- field_defn.mutation = @resolver_class
553
- end
554
- field_defn.metadata[:resolver] = @resolver_class
555
- end
556
-
557
- if !@trace.nil?
558
- field_defn.trace = @trace
559
- end
560
-
561
- if @relay_node_field
562
- field_defn.relay_node_field = @relay_node_field
563
- end
564
-
565
- if @relay_nodes_field
566
- field_defn.relay_nodes_field = @relay_nodes_field
567
- end
568
-
569
- if @legacy_edge_class
570
- field_defn.edge_class = @legacy_edge_class
571
- end
572
-
573
- field_defn.resolve = self.method(:resolve_field)
574
- field_defn.connection = connection?
575
- field_defn.connection_max_page_size = max_page_size
576
- field_defn.introspection = @introspection
577
- field_defn.complexity = @complexity
578
- field_defn.subscription_scope = @subscription_scope
579
- field_defn.ast_node = ast_node
580
-
581
- all_argument_definitions.each do |defn|
582
- arg_graphql = defn.deprecated_to_graphql
583
- field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
584
- end
603
+ # @return [Boolean] True if this field's {#default_page_size} should override the schema default.
604
+ def has_default_page_size?
605
+ !NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
606
+ end
585
607
 
586
- # Support a passed-in proc, one way or another
587
- @resolve_proc = if @resolve
588
- @resolve
589
- elsif @function
590
- @function
591
- elsif @field
592
- @field.resolve_proc
608
+ # @return [Integer, nil] Applied to connections if {#has_default_page_size?}
609
+ def default_page_size
610
+ if !NOT_CONFIGURED.equal?(@default_page_size)
611
+ @default_page_size
612
+ elsif @resolver_class && @resolver_class.has_default_page_size?
613
+ @resolver_class.default_page_size
614
+ else
615
+ nil
593
616
  end
617
+ end
594
618
 
595
- # Ok, `self` isn't a class, but this is for consistency with the classes
596
- field_defn.metadata[:type_class] = self
597
- field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
598
- field_defn
619
+ def freeze
620
+ type
621
+ owner_type
622
+ arguments_statically_coercible?
623
+ connection?
624
+ super
599
625
  end
600
626
 
601
627
  class MissingReturnTypeError < GraphQL::Error; end
602
628
  attr_writer :type
603
629
 
604
- def type
605
- @type ||= if @function
606
- Member::BuildType.parse_type(@function.type, null: false)
607
- elsif @field
608
- Member::BuildType.parse_type(@field.type, null: false)
609
- elsif @return_type_expr.nil?
610
- # Not enough info to determine type
611
- message = "Can't determine the return type for #{self.path}"
630
+ # Get or set the return type of this field.
631
+ #
632
+ # It may return nil if no type was configured or if the given definition block wasn't called yet.
633
+ # @param new_type [Module, GraphQL::Schema::NonNull, GraphQL::Schema::List] A GraphQL return type
634
+ # @return [Module, GraphQL::Schema::NonNull, GraphQL::Schema::List, nil] the configured type for this field
635
+ def type(new_type = NOT_CONFIGURED)
636
+ if NOT_CONFIGURED.equal?(new_type)
612
637
  if @resolver_class
613
- message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
638
+ return_type = @return_type_expr || @resolver_class.type_expr
639
+ if return_type.nil?
640
+ raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
641
+ end
642
+ nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
643
+ Member::BuildType.parse_type(return_type, null: nullable)
644
+ elsif !@return_type_expr.nil?
645
+ @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
614
646
  end
615
- raise MissingReturnTypeError, message
616
647
  else
617
- Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
648
+ @return_type_expr = new_type
649
+ # If `type` is set in the definition block, then the `connection_extension: ...` given as a keyword won't be used, hmm...
650
+ # Also, arguments added by `connection_extension` will clobber anything previously defined,
651
+ # so `type(...)` should go first.
652
+ set_pagination_extensions(connection_extension: self.class.connection_extension)
618
653
  end
619
654
  rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
620
655
  # Let this propagate up
@@ -631,29 +666,22 @@ module GraphQL
631
666
  end
632
667
  end
633
668
 
634
- def accessible?(context)
635
- if @resolver_class
636
- @resolver_class.accessible?(context)
637
- else
638
- true
639
- end
640
- end
641
-
642
669
  def authorized?(object, args, context)
643
670
  if @resolver_class
644
671
  # The resolver _instance_ will check itself during `resolve()`
645
672
  @resolver_class.authorized?(object, context)
646
673
  else
647
- if (arg_values = context[:current_arguments])
648
- # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
649
- using_arg_values = true
650
- arg_values = arg_values.argument_values
651
- else
652
- arg_values = args
653
- using_arg_values = false
654
- end
655
674
  if args.size > 0
656
- args = context.warden.arguments(self)
675
+ if (arg_values = context[:current_arguments])
676
+ # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
677
+ using_arg_values = true
678
+ arg_values = arg_values.argument_values
679
+ else
680
+ arg_values = args
681
+ using_arg_values = false
682
+ end
683
+
684
+ args = context.types.arguments(self)
657
685
  args.each do |arg|
658
686
  arg_key = arg.keyword
659
687
  if arg_values.key?(arg_key)
@@ -682,70 +710,117 @@ module GraphQL
682
710
  end
683
711
  end
684
712
 
685
- # Implement {GraphQL::Field}'s resolve API.
686
- #
687
- # Eventually, we might hook up field instances to execution in another way. TBD.
688
- # @see #resolve for how the interpreter hooks up to it
689
- def resolve_field(obj, args, ctx)
690
- ctx.schema.after_lazy(obj) do |after_obj|
691
- # First, apply auth ...
692
- query_ctx = ctx.query.context
693
- # Some legacy fields can have `nil` here, not exactly sure why.
694
- # @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
695
- inner_obj = after_obj && after_obj.object
696
- ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
697
- if authorized?(inner_obj, ruby_args, query_ctx)
698
- # Then if it passed, resolve the field
699
- if @resolve_proc
700
- # Might be nil, still want to call the func in that case
701
- with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
702
- # Pass the GraphQL args here for compatibility:
703
- @resolve_proc.call(extended_obj, args, ctx)
704
- end
705
- else
706
- public_send_field(after_obj, ruby_args, query_ctx)
707
- end
708
- else
709
- err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
710
- query_ctx.schema.unauthorized_field(err)
711
- end
712
- end
713
- end
714
- end
715
-
716
713
  # This method is called by the interpreter for each field.
717
714
  # You can extend it in your base field classes.
718
715
  # @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
719
716
  # @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
720
717
  # @param ctx [GraphQL::Query::Context]
721
- def resolve(object, args, ctx)
722
- if @resolve_proc
723
- raise "Can't run resolve proc for #{path} when using GraphQL::Execution::Interpreter"
724
- end
725
- begin
726
- # Unwrap the GraphQL object to get the application object.
727
- application_object = object.object
718
+ def resolve(object, args, query_ctx)
719
+ # Unwrap the GraphQL object to get the application object.
720
+ application_object = object.object
721
+ method_receiver = nil
722
+ method_to_call = nil
723
+ method_args = nil
724
+
725
+ @own_validators && Schema::Validator.validate!(validators, application_object, query_ctx, args)
726
+
727
+ query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
728
+ if is_authorized
729
+ with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
730
+ method_args = ruby_kwargs
731
+ if @resolver_class
732
+ if obj.is_a?(GraphQL::Schema::Object)
733
+ obj = obj.object
734
+ end
735
+ obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
736
+ end
728
737
 
729
- Schema::Validator.validate!(validators, application_object, ctx, args)
738
+ inner_object = obj.object
730
739
 
731
- ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
732
- if is_authorized
733
- public_send_field(object, args, ctx)
734
- else
735
- raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
740
+ if !NOT_CONFIGURED.equal?(@hash_key)
741
+ hash_value = if inner_object.is_a?(Hash)
742
+ inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
743
+ elsif inner_object.respond_to?(:[])
744
+ inner_object[@hash_key]
745
+ else
746
+ nil
747
+ end
748
+ if hash_value == false
749
+ hash_value
750
+ else
751
+ hash_value || (@fallback_value != NOT_CONFIGURED ? @fallback_value : nil)
752
+ end
753
+ elsif obj.respond_to?(resolver_method)
754
+ method_to_call = resolver_method
755
+ method_receiver = obj
756
+ # Call the method with kwargs, if there are any
757
+ if !ruby_kwargs.empty?
758
+ obj.public_send(resolver_method, **ruby_kwargs)
759
+ else
760
+ obj.public_send(resolver_method)
761
+ end
762
+ elsif inner_object.is_a?(Hash)
763
+ if @dig_keys
764
+ inner_object.dig(*@dig_keys)
765
+ elsif inner_object.key?(@method_sym)
766
+ inner_object[@method_sym]
767
+ elsif inner_object.key?(@method_str) || !inner_object.default_proc.nil?
768
+ inner_object[@method_str]
769
+ elsif @fallback_value != NOT_CONFIGURED
770
+ @fallback_value
771
+ else
772
+ nil
773
+ end
774
+ elsif inner_object.respond_to?(@method_sym)
775
+ method_to_call = @method_sym
776
+ method_receiver = obj.object
777
+ if !ruby_kwargs.empty?
778
+ inner_object.public_send(@method_sym, **ruby_kwargs)
779
+ else
780
+ inner_object.public_send(@method_sym)
781
+ end
782
+ elsif @fallback_value != NOT_CONFIGURED
783
+ @fallback_value
784
+ else
785
+ raise <<-ERR
786
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
787
+
788
+ - `#{obj.class}##{resolver_method}`, which did not exist
789
+ - `#{inner_object.class}##{@method_sym}`, which did not exist
790
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
791
+
792
+ To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
793
+ ERR
794
+ end
736
795
  end
796
+ else
797
+ raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
737
798
  end
738
- rescue GraphQL::UnauthorizedFieldError => err
739
- err.field ||= self
740
- ctx.schema.unauthorized_field(err)
741
- rescue GraphQL::UnauthorizedError => err
742
- ctx.schema.unauthorized_object(err)
743
799
  end
800
+ rescue GraphQL::UnauthorizedFieldError => err
801
+ err.field ||= self
802
+ begin
803
+ query_ctx.schema.unauthorized_field(err)
804
+ rescue GraphQL::ExecutionError => err
805
+ err
806
+ end
807
+ rescue GraphQL::UnauthorizedError => err
808
+ begin
809
+ query_ctx.schema.unauthorized_object(err)
810
+ rescue GraphQL::ExecutionError => err
811
+ err
812
+ end
813
+ rescue ArgumentError
814
+ if method_receiver && method_to_call
815
+ assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
816
+ end
817
+ # if the line above doesn't raise, re-raise
818
+ raise
744
819
  rescue GraphQL::ExecutionError => err
745
820
  err
746
821
  end
747
822
 
748
- # @param ctx [GraphQL::Query::Context::FieldResolutionContext]
823
+ # @param ctx [GraphQL::Query::Context]
749
824
  def fetch_extra(extra_name, ctx)
750
825
  if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
751
826
  self.public_send(extra_name)
@@ -758,129 +833,6 @@ module GraphQL
758
833
 
759
834
  private
760
835
 
761
- NO_ARGS = {}.freeze
762
-
763
- # Convert a GraphQL arguments instance into a Ruby-style hash.
764
- #
765
- # @param obj [GraphQL::Schema::Object] The object where this field is being resolved
766
- # @param graphql_args [GraphQL::Query::Arguments]
767
- # @param field_ctx [GraphQL::Query::Context::FieldResolutionContext]
768
- # @return [Hash<Symbol => Any>]
769
- def to_ruby_args(obj, graphql_args, field_ctx)
770
- if graphql_args.any? || @extras.any?
771
- # Splat the GraphQL::Arguments to Ruby keyword arguments
772
- ruby_kwargs = graphql_args.to_kwargs
773
- maybe_lazies = []
774
- # Apply any `prepare` methods. Not great code organization, can this go somewhere better?
775
- arguments(field_ctx).each do |name, arg_defn|
776
- ruby_kwargs_key = arg_defn.keyword
777
-
778
- if ruby_kwargs.key?(ruby_kwargs_key)
779
- loads = arg_defn.loads
780
- value = ruby_kwargs[ruby_kwargs_key]
781
- loaded_value = if loads && !arg_defn.from_resolver?
782
- if arg_defn.type.list?
783
- loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
784
- field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
785
- else
786
- load_application_object(arg_defn, loads, value, field_ctx.query.context)
787
- end
788
- elsif arg_defn.type.list? && value.is_a?(Array)
789
- field_ctx.schema.after_any_lazies(value, &:itself)
790
- else
791
- value
792
- end
793
-
794
- maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
795
- prepared_value = if arg_defn.prepare
796
- arg_defn.prepare_value(obj, loaded_value)
797
- else
798
- loaded_value
799
- end
800
-
801
- ruby_kwargs[ruby_kwargs_key] = prepared_value
802
- end
803
- end
804
- end
805
-
806
- @extras.each do |extra_arg|
807
- ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
808
- end
809
-
810
- field_ctx.schema.after_any_lazies(maybe_lazies) do
811
- ruby_kwargs
812
- end
813
- else
814
- NO_ARGS
815
- end
816
- end
817
-
818
- def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
819
- with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
820
- begin
821
- method_receiver = nil
822
- method_to_call = nil
823
- if @resolver_class
824
- if obj.is_a?(GraphQL::Schema::Object)
825
- obj = obj.object
826
- end
827
- obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
828
- end
829
-
830
- # Find a way to resolve this field, checking:
831
- #
832
- # - A method on the type instance;
833
- # - Hash keys, if the wrapped object is a hash or responds to `#[]`
834
- # - A method on the wrapped object;
835
- # - Or, raise not implemented.
836
- #
837
- if obj.respond_to?(@resolver_method)
838
- method_to_call = @resolver_method
839
- method_receiver = obj
840
- # Call the method with kwargs, if there are any
841
- if ruby_kwargs.any?
842
- obj.public_send(@resolver_method, **ruby_kwargs)
843
- else
844
- obj.public_send(@resolver_method)
845
- end
846
- elsif obj.object.is_a?(Hash)
847
- inner_object = obj.object
848
- if @dig_keys
849
- inner_object.dig(*@dig_keys)
850
- elsif inner_object.key?(@method_sym)
851
- inner_object[@method_sym]
852
- else
853
- inner_object[@method_str]
854
- end
855
- elsif defined?(@hash_key) && obj.object.respond_to?(:[])
856
- obj.object[@hash_key]
857
- elsif obj.object.respond_to?(@method_sym)
858
- method_to_call = @method_sym
859
- method_receiver = obj.object
860
- if ruby_kwargs.any?
861
- obj.object.public_send(@method_sym, **ruby_kwargs)
862
- else
863
- obj.object.public_send(@method_sym)
864
- end
865
- else
866
- raise <<-ERR
867
- Failed to implement #{@owner.graphql_name}.#{@name}, tried:
868
-
869
- - `#{obj.class}##{@resolver_method}`, which did not exist
870
- - `#{obj.object.class}##{@method_sym}`, which did not exist
871
- - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
872
-
873
- To implement this field, define one of the methods above (and check for typos)
874
- ERR
875
- end
876
- rescue ArgumentError
877
- assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
878
- # if the line above doesn't raise, re-raise
879
- raise
880
- end
881
- end
882
- end
883
-
884
836
  def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
885
837
  method_defn = receiver.method(method_name)
886
838
  unsatisfied_ruby_kwargs = ruby_kwargs.dup
@@ -909,9 +861,9 @@ module GraphQL
909
861
  unsatisfied_ruby_kwargs.clear
910
862
  end
911
863
 
912
- if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
864
+ if !unsatisfied_ruby_kwargs.empty? || !unsatisfied_method_params.empty?
913
865
  raise FieldImplementationFailed.new, <<-ERR
914
- Failed to call #{method_name} on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
866
+ Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
915
867
 
916
868
  #{ unsatisfied_ruby_kwargs
917
869
  .map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
@@ -921,6 +873,17 @@ ERR
921
873
  end
922
874
  end
923
875
 
876
+ class ExtendedState
877
+ def initialize(args, object)
878
+ @arguments = args
879
+ @object = object
880
+ @memos = nil
881
+ @added_extras = nil
882
+ end
883
+
884
+ attr_accessor :arguments, :object, :memos, :added_extras
885
+ end
886
+
924
887
  # Wrap execution with hooks.
925
888
  # Written iteratively to avoid big stack traces.
926
889
  # @return [Object] Whatever the
@@ -931,20 +894,20 @@ ERR
931
894
  # This is a hack to get the _last_ value for extended obj and args,
932
895
  # in case one of the extensions doesn't `yield`.
933
896
  # (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
934
- extended = { args: args, obj: obj, memos: nil, added_extras: nil }
897
+ extended = ExtendedState.new(args, obj)
935
898
  value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
936
- if (added_extras = extended[:added_extras])
899
+ if (added_extras = extended.added_extras)
937
900
  args = args.dup
938
901
  added_extras.each { |e| args.delete(e) }
939
902
  end
940
903
  yield(obj, args)
941
904
  end
942
905
 
943
- extended_obj = extended[:obj]
944
- extended_args = extended[:args]
945
- memos = extended[:memos] || EMPTY_HASH
906
+ extended_obj = extended.object
907
+ extended_args = extended.arguments # rubocop:disable Development/ContextIsPassedCop
908
+ memos = extended.memos || EMPTY_HASH
946
909
 
947
- ctx.schema.after_lazy(value) do |resolved_value|
910
+ ctx.query.after_lazy(value) do |resolved_value|
948
911
  idx = 0
949
912
  @extensions.each do |ext|
950
913
  memo = memos[idx]
@@ -962,23 +925,55 @@ ERR
962
925
  if extension
963
926
  extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
964
927
  if memo
965
- memos = extended[:memos] ||= {}
928
+ memos = extended.memos ||= {}
966
929
  memos[idx] = memo
967
930
  end
968
931
 
969
932
  if (extras = extension.added_extras)
970
- ae = extended[:added_extras] ||= []
933
+ ae = extended.added_extras ||= []
971
934
  ae.concat(extras)
972
935
  end
973
936
 
974
- extended[:obj] = extended_obj
975
- extended[:args] = extended_args
937
+ extended.object = extended_obj
938
+ extended.arguments = extended_args
976
939
  run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
977
940
  end
978
941
  else
979
942
  yield(obj, args)
980
943
  end
981
944
  end
945
+
946
+ def apply_own_complexity_to(child_complexity, query, nodes)
947
+ case (own_complexity = complexity)
948
+ when Numeric
949
+ own_complexity + child_complexity
950
+ when Proc
951
+ arguments = query.arguments_for(nodes.first, self)
952
+ if arguments.is_a?(GraphQL::ExecutionError)
953
+ return child_complexity
954
+ elsif arguments.respond_to?(:keyword_arguments)
955
+ arguments = arguments.keyword_arguments
956
+ end
957
+
958
+ own_complexity.call(query.context, arguments, child_complexity)
959
+ else
960
+ raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
961
+ end
962
+ end
963
+
964
+ def set_pagination_extensions(connection_extension:)
965
+ # This should run before connection extension,
966
+ # but should it run after the definition block?
967
+ if scoped?
968
+ self.extension(ScopeExtension, call_after_define: false)
969
+ end
970
+
971
+ # The problem with putting this after the definition_block
972
+ # is that it would override arguments
973
+ if connection? && connection_extension
974
+ self.extension(connection_extension, call_after_define: false)
975
+ end
976
+ end
982
977
  end
983
978
  end
984
979
  end