graphql 2.0.32 → 2.5.22

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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  4. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  5. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  6. data/lib/generators/graphql/install_generator.rb +49 -0
  7. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  8. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  9. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  10. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  11. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  12. data/lib/generators/graphql/templates/base_field.erb +2 -0
  13. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  14. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  15. data/lib/generators/graphql/templates/base_object.erb +2 -0
  16. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  17. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  18. data/lib/generators/graphql/templates/base_union.erb +2 -0
  19. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +5 -0
  26. data/lib/generators/graphql/type_generator.rb +1 -1
  27. data/lib/graphql/analysis/analyzer.rb +90 -0
  28. data/lib/graphql/analysis/field_usage.rb +82 -0
  29. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  30. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  31. data/lib/graphql/analysis/query_complexity.rb +263 -0
  32. data/lib/graphql/analysis/query_depth.rb +58 -0
  33. data/lib/graphql/analysis/visitor.rb +280 -0
  34. data/lib/graphql/analysis.rb +95 -1
  35. data/lib/graphql/autoload.rb +38 -0
  36. data/lib/graphql/backtrace/table.rb +118 -55
  37. data/lib/graphql/backtrace.rb +1 -19
  38. data/lib/graphql/coercion_error.rb +1 -9
  39. data/lib/graphql/current.rb +57 -0
  40. data/lib/graphql/dashboard/application_controller.rb +41 -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/landings_controller.rb +9 -0
  44. data/lib/graphql/dashboard/limiters.rb +93 -0
  45. data/lib/graphql/dashboard/operation_store.rb +199 -0
  46. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  47. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  48. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  49. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  50. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  51. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  52. data/lib/graphql/dashboard/statics/icon.png +0 -0
  53. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  54. data/lib/graphql/dashboard/subscriptions.rb +97 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  65. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  66. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  67. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  68. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  69. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  70. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  71. data/lib/graphql/dashboard.rb +96 -0
  72. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  73. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  74. data/lib/graphql/dataloader/async_dataloader.rb +112 -0
  75. data/lib/graphql/dataloader/null_dataloader.rb +55 -10
  76. data/lib/graphql/dataloader/request.rb +5 -0
  77. data/lib/graphql/dataloader/source.rb +35 -12
  78. data/lib/graphql/dataloader.rb +224 -149
  79. data/lib/graphql/date_encoding_error.rb +1 -1
  80. data/lib/graphql/dig.rb +2 -1
  81. data/lib/graphql/duration_encoding_error.rb +16 -0
  82. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  83. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  84. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  85. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
  86. data/lib/graphql/execution/interpreter/runtime.rb +363 -434
  87. data/lib/graphql/execution/interpreter.rb +91 -164
  88. data/lib/graphql/execution/lookahead.rb +105 -31
  89. data/lib/graphql/execution/multiplex.rb +7 -6
  90. data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
  91. data/lib/graphql/execution/next/load_argument_step.rb +60 -0
  92. data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
  93. data/lib/graphql/execution/next/runner.rb +389 -0
  94. data/lib/graphql/execution/next/selections_step.rb +37 -0
  95. data/lib/graphql/execution/next.rb +70 -0
  96. data/lib/graphql/execution.rb +1 -0
  97. data/lib/graphql/execution_error.rb +13 -10
  98. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  99. data/lib/graphql/introspection/directive_type.rb +7 -3
  100. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  101. data/lib/graphql/introspection/entry_points.rb +20 -6
  102. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  103. data/lib/graphql/introspection/field_type.rb +13 -5
  104. data/lib/graphql/introspection/input_value_type.rb +21 -13
  105. data/lib/graphql/introspection/schema_type.rb +8 -11
  106. data/lib/graphql/introspection/type_type.rb +64 -28
  107. data/lib/graphql/invalid_name_error.rb +1 -1
  108. data/lib/graphql/invalid_null_error.rb +26 -17
  109. data/lib/graphql/language/block_string.rb +34 -18
  110. data/lib/graphql/language/cache.rb +13 -0
  111. data/lib/graphql/language/comment.rb +18 -0
  112. data/lib/graphql/language/definition_slice.rb +1 -1
  113. data/lib/graphql/language/document_from_schema_definition.rb +90 -61
  114. data/lib/graphql/language/lexer.rb +319 -193
  115. data/lib/graphql/language/nodes.rb +136 -77
  116. data/lib/graphql/language/parser.rb +807 -1985
  117. data/lib/graphql/language/printer.rb +324 -151
  118. data/lib/graphql/language/sanitized_printer.rb +21 -23
  119. data/lib/graphql/language/static_visitor.rb +171 -0
  120. data/lib/graphql/language/visitor.rb +23 -83
  121. data/lib/graphql/language.rb +71 -1
  122. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  123. data/lib/graphql/pagination/array_connection.rb +6 -6
  124. data/lib/graphql/pagination/connection.rb +30 -1
  125. data/lib/graphql/pagination/connections.rb +32 -0
  126. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  127. data/lib/graphql/query/context/scoped_context.rb +101 -0
  128. data/lib/graphql/query/context.rb +82 -144
  129. data/lib/graphql/query/null_context.rb +15 -18
  130. data/lib/graphql/query/partial.rb +179 -0
  131. data/lib/graphql/query/validation_pipeline.rb +4 -4
  132. data/lib/graphql/query/variable_validation_error.rb +1 -1
  133. data/lib/graphql/query/variables.rb +3 -3
  134. data/lib/graphql/query.rb +126 -81
  135. data/lib/graphql/railtie.rb +16 -6
  136. data/lib/graphql/rake_task.rb +3 -12
  137. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  138. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  139. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  140. data/lib/graphql/rubocop.rb +2 -0
  141. data/lib/graphql/schema/addition.rb +26 -13
  142. data/lib/graphql/schema/always_visible.rb +7 -2
  143. data/lib/graphql/schema/argument.rb +75 -9
  144. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  145. data/lib/graphql/schema/build_from_definition.rb +123 -60
  146. data/lib/graphql/schema/directive/flagged.rb +4 -2
  147. data/lib/graphql/schema/directive/one_of.rb +12 -0
  148. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  149. data/lib/graphql/schema/directive.rb +54 -2
  150. data/lib/graphql/schema/enum.rb +110 -27
  151. data/lib/graphql/schema/enum_value.rb +10 -2
  152. data/lib/graphql/schema/field/connection_extension.rb +15 -49
  153. data/lib/graphql/schema/field/scope_extension.rb +23 -7
  154. data/lib/graphql/schema/field.rb +245 -118
  155. data/lib/graphql/schema/field_extension.rb +34 -1
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +116 -60
  158. data/lib/graphql/schema/interface.rb +34 -16
  159. data/lib/graphql/schema/introspection_system.rb +8 -17
  160. data/lib/graphql/schema/late_bound_type.rb +4 -0
  161. data/lib/graphql/schema/list.rb +3 -3
  162. data/lib/graphql/schema/loader.rb +3 -4
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
  164. data/lib/graphql/schema/member/has_arguments.rb +132 -100
  165. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  166. data/lib/graphql/schema/member/has_dataloader.rb +99 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  168. data/lib/graphql/schema/member/has_directives.rb +4 -4
  169. data/lib/graphql/schema/member/has_fields.rb +115 -15
  170. data/lib/graphql/schema/member/has_interfaces.rb +26 -12
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +1 -1
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  176. data/lib/graphql/schema/member/validates_input.rb +3 -3
  177. data/lib/graphql/schema/member.rb +6 -0
  178. data/lib/graphql/schema/mutation.rb +7 -0
  179. data/lib/graphql/schema/object.rb +34 -8
  180. data/lib/graphql/schema/printer.rb +9 -7
  181. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  182. data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
  183. data/lib/graphql/schema/resolver.rb +90 -32
  184. data/lib/graphql/schema/scalar.rb +4 -9
  185. data/lib/graphql/schema/subscription.rb +63 -10
  186. data/lib/graphql/schema/timeout.rb +19 -2
  187. data/lib/graphql/schema/type_expression.rb +2 -2
  188. data/lib/graphql/schema/union.rb +2 -2
  189. data/lib/graphql/schema/unique_within_type.rb +1 -1
  190. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  191. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  192. data/lib/graphql/schema/validator.rb +3 -1
  193. data/lib/graphql/schema/visibility/migration.rb +188 -0
  194. data/lib/graphql/schema/visibility/profile.rb +445 -0
  195. data/lib/graphql/schema/visibility/visit.rb +190 -0
  196. data/lib/graphql/schema/visibility.rb +311 -0
  197. data/lib/graphql/schema/warden.rb +275 -103
  198. data/lib/graphql/schema.rb +950 -210
  199. data/lib/graphql/static_validation/all_rules.rb +3 -3
  200. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  201. data/lib/graphql/static_validation/literal_validator.rb +6 -7
  202. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  203. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  204. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  205. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  206. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  207. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  208. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  209. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  210. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  211. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  212. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  213. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  214. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  215. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  216. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  217. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  218. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  219. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  220. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  221. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  222. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  223. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  224. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  225. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  226. data/lib/graphql/static_validation/validation_context.rb +21 -5
  227. data/lib/graphql/static_validation/validator.rb +9 -1
  228. data/lib/graphql/static_validation.rb +0 -1
  229. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
  230. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  231. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  232. data/lib/graphql/subscriptions/event.rb +21 -4
  233. data/lib/graphql/subscriptions/serialize.rb +3 -1
  234. data/lib/graphql/subscriptions.rb +21 -17
  235. data/lib/graphql/testing/helpers.rb +161 -0
  236. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  237. data/lib/graphql/testing.rb +3 -0
  238. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  239. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  240. data/lib/graphql/tracing/appoptics_trace.rb +7 -3
  241. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  242. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  243. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  244. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  245. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  246. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  247. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  248. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  249. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  250. data/lib/graphql/tracing/detailed_trace.rb +156 -0
  251. data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
  252. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  253. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  254. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  255. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  256. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  257. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  258. data/lib/graphql/tracing/null_trace.rb +9 -0
  259. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  260. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  261. data/lib/graphql/tracing/perfetto_trace.rb +864 -0
  262. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  263. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
  264. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  265. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  266. data/lib/graphql/tracing/scout_trace.rb +32 -58
  267. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  268. data/lib/graphql/tracing/sentry_trace.rb +82 -0
  269. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  270. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  271. data/lib/graphql/tracing/trace.rb +112 -1
  272. data/lib/graphql/tracing.rb +31 -28
  273. data/lib/graphql/type_kinds.rb +2 -1
  274. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  275. data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
  276. data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
  277. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  278. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  279. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  280. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  281. data/lib/graphql/types.rb +18 -10
  282. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  283. data/lib/graphql/unauthorized_error.rb +5 -1
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +71 -54
  286. data/readme.md +12 -2
  287. metadata +233 -37
  288. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  289. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  290. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  291. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  292. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  293. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  294. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  295. data/lib/graphql/analysis/ast.rb +0 -81
  296. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  297. data/lib/graphql/backtrace/trace.rb +0 -96
  298. data/lib/graphql/backtrace/tracer.rb +0 -80
  299. data/lib/graphql/deprecation.rb +0 -9
  300. data/lib/graphql/filter.rb +0 -59
  301. data/lib/graphql/language/parser.y +0 -560
  302. data/lib/graphql/language/token.rb +0 -34
  303. data/lib/graphql/schema/base_64_bp.rb +0 -26
  304. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  305. data/lib/graphql/schema/null_mask.rb +0 -11
  306. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  307. data/lib/graphql/static_validation/type_stack.rb +0 -216
  308. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -14,63 +14,53 @@ module GraphQL
14
14
  cls.extend(ClassConfigured)
15
15
  end
16
16
 
17
- # @see {GraphQL::Schema::Argument#initialize} for parameters
18
- # @return [GraphQL::Schema::Argument] An instance of {argument_class}, created from `*args`
19
- def argument(*args, **kwargs, &block)
20
- kwargs[:owner] = self
21
- loads = kwargs[:loads]
22
- if loads
23
- name = args[0]
24
- name_as_string = name.to_s
25
-
26
- inferred_arg_name = case name_as_string
17
+ # @param arg_name [Symbol] The underscore-cased name of this argument, `name:` keyword also accepted
18
+ # @param type_expr The GraphQL type of this argument; `type:` keyword also accepted
19
+ # @param desc [String] Argument description, `description:` keyword also accepted
20
+ # @option kwargs [Boolean, :nullable] :required if true, this argument is non-null; if false, this argument is nullable. If `:nullable`, then the argument must be provided, though it may be `null`.
21
+ # @option kwargs [String] :description Positional argument also accepted
22
+ # @option kwargs [Class, Array<Class>] :type Input type; positional argument also accepted
23
+ # @option kwargs [Symbol] :name positional argument also accepted
24
+ # @option kwargs [Object] :default_value
25
+ # @option kwargs [Class, Array<Class>] :loads A GraphQL type to load for the given ID when one is present
26
+ # @option kwargs [Symbol] :as Override the keyword name when passed to a method
27
+ # @option kwargs [Symbol] :prepare A method to call to transform this argument's valuebefore sending it to field resolution
28
+ # @option kwargs [Boolean] :camelize if true, the name will be camelized when building the schema
29
+ # @option kwargs [Boolean] :from_resolver if true, a Resolver class defined this argument
30
+ # @option kwargs [Hash{Class => Hash}] :directives
31
+ # @option kwargs [String] :deprecation_reason
32
+ # @option kwargs [String] :comment Private, used by GraphQL-Ruby when parsing GraphQL schema files
33
+ # @option kwargs [GraphQL::Language::Nodes::InputValueDefinition] :ast_node Private, used by GraphQL-Ruby when parsing schema files
34
+ # @option kwargs [Hash, nil] :validates Options for building validators, if any should be applied
35
+ # @option kwargs [Boolean] :replace_null_with_default if `true`, incoming values of `null` will be replaced with the configured `default_value`
36
+ # @param definition_block [Proc] Called with the newly-created {Argument}
37
+ # @param kwargs [Hash] Keywords for defining an argument. Any keywords not documented here must be handled by your base Argument class.
38
+ # @return [GraphQL::Schema::Argument] An instance of {argument_class} created from these arguments
39
+ def argument(arg_name = nil, type_expr = nil, desc = nil, **kwargs, &definition_block)
40
+ if kwargs[:loads]
41
+ loads_name = arg_name || kwargs[:name]
42
+ loads_name_as_string = loads_name.to_s
43
+
44
+ inferred_arg_name = case loads_name_as_string
27
45
  when /_id$/
28
- name_as_string.sub(/_id$/, "").to_sym
46
+ loads_name_as_string.sub(/_id$/, "").to_sym
29
47
  when /_ids$/
30
- name_as_string.sub(/_ids$/, "")
48
+ loads_name_as_string.sub(/_ids$/, "")
31
49
  .sub(/([^s])$/, "\\1s")
32
50
  .to_sym
33
51
  else
34
- name
52
+ loads_name
35
53
  end
36
54
 
37
55
  kwargs[:as] ||= inferred_arg_name
38
56
  end
39
- arg_defn = self.argument_class.new(*args, **kwargs, &block)
57
+ kwargs[:owner] = self
58
+ arg_defn = self.argument_class.new(
59
+ arg_name, type_expr, desc,
60
+ **kwargs,
61
+ &definition_block
62
+ )
40
63
  add_argument(arg_defn)
41
-
42
- if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
43
- method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
44
- "self."
45
- elsif self < GraphQL::Schema::Resolver
46
- ""
47
- else
48
- raise "Unexpected argument owner: #{self}"
49
- end
50
- if loads && arg_defn.type.list?
51
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
52
- def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
53
- argument = get_argument("#{arg_defn.graphql_name}")
54
- (context || self.context).query.after_lazy(values) do |values2|
55
- GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
56
- end
57
- end
58
- RUBY
59
- elsif loads
60
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
- def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
62
- argument = get_argument("#{arg_defn.graphql_name}")
63
- load_application_object(argument, value, context || self.context)
64
- end
65
- RUBY
66
- else
67
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
68
- def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
69
- value
70
- end
71
- RUBY
72
- end
73
- end
74
64
  arg_defn
75
65
  end
76
66
 
@@ -109,8 +99,8 @@ module GraphQL
109
99
  end
110
100
 
111
101
  # @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
112
- def arguments(context = GraphQL::Query::NullContext)
113
- if own_arguments.any?
102
+ def arguments(context = GraphQL::Query::NullContext.instance, _require_defined_arguments = nil)
103
+ if !own_arguments.empty?
114
104
  own_arguments_that_apply = {}
115
105
  own_arguments.each do |name, args_entry|
116
106
  if (visible_defn = Warden.visible_entry?(:visible_argument?, args_entry, context))
@@ -122,6 +112,10 @@ module GraphQL
122
112
  own_arguments_that_apply || own_arguments
123
113
  end
124
114
 
115
+ def any_arguments?
116
+ !own_arguments.empty?
117
+ end
118
+
125
119
  module ClassConfigured
126
120
  def inherited(child_class)
127
121
  super
@@ -129,12 +123,12 @@ module GraphQL
129
123
  end
130
124
 
131
125
  module InheritedArguments
132
- def arguments(context = GraphQL::Query::NullContext)
133
- own_arguments = super
134
- inherited_arguments = superclass.arguments(context)
126
+ def arguments(context = GraphQL::Query::NullContext.instance, require_defined_arguments = true)
127
+ own_arguments = super(context, require_defined_arguments)
128
+ inherited_arguments = superclass.arguments(context, false)
135
129
 
136
- if own_arguments.any?
137
- if inherited_arguments.any?
130
+ if !own_arguments.empty?
131
+ if !inherited_arguments.empty?
138
132
  # Local definitions override inherited ones
139
133
  inherited_arguments.merge(own_arguments)
140
134
  else
@@ -145,6 +139,10 @@ module GraphQL
145
139
  end
146
140
  end
147
141
 
142
+ def any_arguments?
143
+ super || superclass.any_arguments?
144
+ end
145
+
148
146
  def all_argument_definitions
149
147
  all_defns = {}
150
148
  ancestors.reverse_each do |ancestor|
@@ -158,12 +156,13 @@ module GraphQL
158
156
  end
159
157
 
160
158
 
161
- def get_argument(argument_name, context = GraphQL::Query::NullContext)
159
+ def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
162
160
  warden = Warden.from_context(context)
161
+ skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
163
162
  for ancestor in ancestors
164
163
  if ancestor.respond_to?(:own_arguments) &&
165
164
  (a = ancestor.own_arguments[argument_name]) &&
166
- (a = Warden.visible_entry?(:visible_argument?, a, context, warden))
165
+ (skip_visible || (a = Warden.visible_entry?(:visible_argument?, a, context, warden)))
167
166
  return a
168
167
  end
169
168
  end
@@ -173,12 +172,12 @@ module GraphQL
173
172
  end
174
173
 
175
174
  module FieldConfigured
176
- def arguments(context = GraphQL::Query::NullContext)
175
+ def arguments(context = GraphQL::Query::NullContext.instance, _require_defined_arguments = nil)
177
176
  own_arguments = super
178
- if defined?(@resolver_class) && @resolver_class
177
+ if @resolver_class
179
178
  inherited_arguments = @resolver_class.field_arguments(context)
180
- if own_arguments.any?
181
- if inherited_arguments.any?
179
+ if !own_arguments.empty?
180
+ if !inherited_arguments.empty?
182
181
  inherited_arguments.merge(own_arguments)
183
182
  else
184
183
  own_arguments
@@ -191,8 +190,12 @@ module GraphQL
191
190
  end
192
191
  end
193
192
 
193
+ def any_arguments?
194
+ super || (@resolver_class && @resolver_class.any_field_arguments?)
195
+ end
196
+
194
197
  def all_argument_definitions
195
- if defined?(@resolver_class) && @resolver_class
198
+ if @resolver_class
196
199
  all_defns = {}
197
200
  @resolver_class.all_field_argument_definitions.each do |arg_defn|
198
201
  key = arg_defn.graphql_name
@@ -218,16 +221,20 @@ module GraphQL
218
221
  end
219
222
 
220
223
  def all_argument_definitions
221
- all_defns = own_arguments.values
222
- all_defns.flatten!
223
- all_defns
224
+ if !own_arguments.empty?
225
+ all_defns = own_arguments.values
226
+ all_defns.flatten!
227
+ all_defns
228
+ else
229
+ EmptyObjects::EMPTY_ARRAY
230
+ end
224
231
  end
225
232
 
226
233
  # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
227
- def get_argument(argument_name, context = GraphQL::Query::NullContext)
234
+ def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
228
235
  warden = Warden.from_context(context)
229
- if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
230
- visible_arg
236
+ if (arg_config = own_arguments[argument_name]) && ((context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)) || (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden)))
237
+ visible_arg || arg_config
231
238
  elsif defined?(@resolver_class) && @resolver_class
232
239
  @resolver_class.get_field_argument(argument_name, context)
233
240
  else
@@ -247,11 +254,11 @@ module GraphQL
247
254
  #
248
255
  # @param values [Hash<String, Object>]
249
256
  # @param context [GraphQL::Query::Context]
250
- # @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
251
- # @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
257
+ # @yield [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
258
+ # @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
252
259
  def coerce_arguments(parent_object, values, context, &block)
253
260
  # Cache this hash to avoid re-merging it
254
- arg_defns = context.warden.arguments(self)
261
+ arg_defns = context.types.arguments(self)
255
262
  total_args_count = arg_defns.size
256
263
 
257
264
  finished_args = nil
@@ -367,41 +374,60 @@ module GraphQL
367
374
  def authorize_application_object(argument, id, context, loaded_application_object)
368
375
  context.query.after_lazy(loaded_application_object) do |application_object|
369
376
  if application_object.nil?
370
- err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
371
- load_application_object_failed(err)
377
+ err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
378
+ application_object = load_application_object_failed(err)
372
379
  end
373
380
  # Double-check that the located object is actually of this type
374
381
  # (Don't want to allow arbitrary access to objects this way)
375
- maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
376
- context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
377
- if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
378
- application_object_type, application_object = resolve_type_result
379
- else
380
- application_object_type = resolve_type_result
381
- # application_object is already assigned
382
- end
383
- possible_object_types = context.warden.possible_types(argument.loads)
384
- if !possible_object_types.include?(application_object_type)
385
- err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
386
- load_application_object_failed(err)
387
- else
388
- # This object was loaded successfully
389
- # and resolved to the right type,
390
- # now apply the `.authorized?` class method if there is one
391
- context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
392
- if authed
393
- application_object
382
+ if application_object.nil?
383
+ nil
384
+ else
385
+ arg_loads_type = argument.loads
386
+ maybe_lazy_resolve_type = context.schema.resolve_type(arg_loads_type, application_object, context)
387
+ context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
388
+ if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
389
+ application_object_type, application_object = resolve_type_result
390
+ else
391
+ application_object_type = resolve_type_result
392
+ # application_object is already assigned
393
+ end
394
+
395
+ passes_possible_types_check = if context.types.loadable?(arg_loads_type, context)
396
+ if arg_loads_type.kind.abstract?
397
+ # This union/interface is used in `loads:` but not otherwise visible to this query
398
+ context.types.loadable_possible_types(arg_loads_type, context).include?(application_object_type)
394
399
  else
395
- err = GraphQL::UnauthorizedError.new(
396
- object: application_object,
397
- type: application_object_type,
398
- context: context,
399
- )
400
- if self.respond_to?(:unauthorized_object)
401
- err.set_backtrace(caller)
402
- unauthorized_object(err)
400
+ true
401
+ end
402
+ else
403
+ context.types.possible_types(arg_loads_type).include?(application_object_type)
404
+ end
405
+ if !passes_possible_types_check
406
+ err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
407
+ application_object = load_application_object_failed(err)
408
+ end
409
+
410
+ if application_object.nil?
411
+ nil
412
+ else
413
+ # This object was loaded successfully
414
+ # and resolved to the right type,
415
+ # now apply the `.authorized?` class method if there is one
416
+ context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
417
+ if authed
418
+ application_object
403
419
  else
404
- raise err
420
+ err = GraphQL::UnauthorizedError.new(
421
+ object: application_object,
422
+ type: application_object_type,
423
+ context: context,
424
+ )
425
+ if self.respond_to?(:unauthorized_object)
426
+ err.set_backtrace(caller)
427
+ unauthorized_object(err)
428
+ else
429
+ raise err
430
+ end
405
431
  end
406
432
  end
407
433
  end
@@ -410,6 +436,12 @@ module GraphQL
410
436
  end
411
437
  end
412
438
 
439
+ # Called when an argument's `loads:` configuration fails to fetch an application object.
440
+ # By default, this method raises the given error, but you can override it to handle failures differently.
441
+ #
442
+ # @param err [GraphQL::LoadApplicationObjectFailedError] The error that occurred
443
+ # @return [Object, nil] If a value is returned, it will be used instead of the failed load
444
+ # @api public
413
445
  def load_application_object_failed(err)
414
446
  raise err
415
447
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Member
5
+ module HasAuthorization
6
+ def self.included(child_class)
7
+ child_class.include(InstanceConfigured)
8
+ end
9
+
10
+ def self.extended(child_class)
11
+ child_class.extend(ClassConfigured)
12
+ child_class.class_exec do
13
+ @authorizes = false
14
+ end
15
+ end
16
+
17
+ def authorized?(object, context)
18
+ true
19
+ end
20
+
21
+ module InstanceConfigured
22
+ def authorizes?(context)
23
+ raise RequiredImplementationMissingError, "#{self.class} must implement #authorizes?(context)"
24
+ end
25
+ end
26
+
27
+ module ClassConfigured
28
+ def authorizes?(context)
29
+ method(:authorized?).owner != GraphQL::Schema::Member::HasAuthorization
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ # @api public
7
+ # Shared methods for working with {Dataloader} inside GraphQL runtime objects.
8
+ module HasDataloader
9
+ # @return [GraphQL::Dataloader] The dataloader for the currently-running query
10
+ def dataloader
11
+ context.dataloader
12
+ end
13
+
14
+ # A shortcut method for loading a key from a source.
15
+ # Identical to `dataloader.with(source_class, *source_args).load(load_key)`
16
+ # @param source_class [Class<GraphQL::Dataloader::Source>]
17
+ # @param source_args [Array<Object>] Any extra parameters defined in `source_class`'s `initialize` method
18
+ # @param load_key [Object] The key to look up using `def fetch`
19
+ def dataload(source_class, *source_args, load_key)
20
+ dataloader.with(source_class, *source_args).load(load_key)
21
+ end
22
+
23
+ # A shortcut method for loading many keys from a source.
24
+ # Identical to `dataloader.with(source_class, *source_args).load_all(load_keys)`
25
+ #
26
+ # @example
27
+ # field :score, Integer, resolve_batch: true
28
+ #
29
+ # def self.score(posts)
30
+ # dataload_all(PostScoreSource, posts.map(&:id))
31
+ # end
32
+ #
33
+ # @param source_class [Class<GraphQL::Dataloader::Source>]
34
+ # @param source_args [Array<Object>] Any extra parameters defined in `source_class`'s `initialize` method
35
+ # @param load_keys [Array<Object>] The keys to look up using `def fetch`
36
+ def dataload_all(source_class, *source_args, load_keys)
37
+ dataloader.with(source_class, *source_args).load_all(load_keys)
38
+ end
39
+
40
+ # Find an object with ActiveRecord via {Dataloader::ActiveRecordSource}.
41
+ # @param model [Class<ActiveRecord::Base>]
42
+ # @param find_by_value [Object] Usually an `id`, might be another value if `find_by:` is also provided
43
+ # @param find_by [Symbol, String] A column name to look the record up by. (Defaults to the model's primary key.)
44
+ # @return [ActiveRecord::Base, nil]
45
+ # @example Finding a record by ID
46
+ # dataload_record(Post, 5) # Like `Post.find(5)`, but dataloaded
47
+ # @example Finding a record by another attribute
48
+ # dataload_record(User, "matz", find_by: :handle) # Like `User.find_by(handle: "matz")`, but dataloaded
49
+ def dataload_record(model, find_by_value, find_by: nil)
50
+ source = if find_by
51
+ dataloader.with(Dataloader::ActiveRecordSource, model, find_by: find_by)
52
+ else
53
+ dataloader.with(Dataloader::ActiveRecordSource, model)
54
+ end
55
+
56
+ source.load(find_by_value)
57
+ end
58
+
59
+ # @see dataload_record Like `dataload_record`, but accepts an Array of `find_by_values`
60
+ def dataload_all_records(model, find_by_values, find_by: nil)
61
+ source = if find_by
62
+ dataloader.with(Dataloader::ActiveRecordSource, model, find_by: find_by)
63
+ else
64
+ dataloader.with(Dataloader::ActiveRecordSource, model)
65
+ end
66
+ source.load_all(find_by_values)
67
+ end
68
+
69
+ # Look up an associated record using a Rails association (via {Dataloader::ActiveRecordAssociationSource})
70
+ # @param association_name [Symbol] A `belongs_to` or `has_one` association. (If a `has_many` association is named here, it will be selected without pagination.)
71
+ # @param record [ActiveRecord::Base] The object that the association belongs to.
72
+ # @param scope [ActiveRecord::Relation] A scope to look up the associated record in
73
+ # @return [ActiveRecord::Base, nil] The associated record, if there is one
74
+ # @example Looking up a belongs_to on the current object
75
+ # dataload_association(:parent) # Equivalent to `object.parent`, but dataloaded
76
+ # @example Looking up an associated record on some other object
77
+ # dataload_association(comment, :post) # Equivalent to `comment.post`, but dataloaded
78
+ def dataload_association(record = object, association_name, scope: nil)
79
+ source = if scope
80
+ dataloader.with(Dataloader::ActiveRecordAssociationSource, association_name, scope)
81
+ else
82
+ dataloader.with(Dataloader::ActiveRecordAssociationSource, association_name)
83
+ end
84
+ source.load(record)
85
+ end
86
+
87
+ # @see dataload_association Like `dataload_assocation` but accepts an Array of records (required param)
88
+ def dataload_all_associations(records, association_name, scope: nil)
89
+ source = if scope
90
+ dataloader.with(Dataloader::ActiveRecordAssociationSource, association_name, scope)
91
+ else
92
+ dataloader.with(Dataloader::ActiveRecordAssociationSource, association_name)
93
+ end
94
+ source.load_all(records)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -18,6 +18,21 @@ module GraphQL
18
18
  directive(GraphQL::Schema::Directive::Deprecated, reason: text)
19
19
  end
20
20
  end
21
+
22
+ def self.extended(child_class)
23
+ super
24
+ child_class.extend(ClassMethods)
25
+ end
26
+
27
+ module ClassMethods
28
+ def deprecation_reason(new_reason = NOT_CONFIGURED)
29
+ if NOT_CONFIGURED.equal?(new_reason)
30
+ super()
31
+ else
32
+ self.deprecation_reason = new_reason
33
+ end
34
+ end
35
+ end
21
36
  end
22
37
  end
23
38
  end
@@ -55,14 +55,14 @@ module GraphQL
55
55
  else
56
56
  GraphQL::EmptyObjects::EMPTY_ARRAY
57
57
  end
58
- if inherited_directives.any? && directives
58
+ if !inherited_directives.empty? && directives
59
59
  dirs = []
60
60
  merge_directives(dirs, inherited_directives)
61
61
  merge_directives(dirs, directives)
62
62
  dirs
63
63
  elsif directives
64
64
  directives
65
- elsif inherited_directives.any?
65
+ elsif !inherited_directives.empty?
66
66
  inherited_directives
67
67
  else
68
68
  GraphQL::EmptyObjects::EMPTY_ARRAY
@@ -71,7 +71,7 @@ module GraphQL
71
71
  dirs = nil
72
72
  schema_member.ancestors.reverse_each do |ancestor|
73
73
  if ancestor.respond_to?(:own_directives) &&
74
- (anc_dirs = ancestor.own_directives).any?
74
+ !(anc_dirs = ancestor.own_directives).empty?
75
75
  dirs ||= []
76
76
  merge_directives(dirs, anc_dirs)
77
77
  end
@@ -91,7 +91,7 @@ module GraphQL
91
91
  private
92
92
 
93
93
  # Modify `target` by adding items from `dirs` such that:
94
- # - Any name conflict is overriden by the incoming member of `dirs`
94
+ # - Any name conflict is overridden by the incoming member of `dirs`
95
95
  # - Any other member of `dirs` is appended
96
96
  # @param target [Array<GraphQL::Schema::Directive>]
97
97
  # @param dirs [Array<GraphQL::Schema::Directive>]