graphql 2.0.31 → 2.6.1

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 (316) 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 +102 -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/field_resolve_step.rb +631 -0
  83. data/lib/graphql/execution/finalize.rb +217 -0
  84. data/lib/graphql/execution/input_values.rb +261 -0
  85. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  86. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  87. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  88. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  89. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
  90. data/lib/graphql/execution/interpreter/runtime.rb +365 -435
  91. data/lib/graphql/execution/interpreter.rb +87 -163
  92. data/lib/graphql/execution/lazy.rb +1 -1
  93. data/lib/graphql/execution/load_argument_step.rb +64 -0
  94. data/lib/graphql/execution/lookahead.rb +105 -31
  95. data/lib/graphql/execution/multiplex.rb +7 -6
  96. data/lib/graphql/execution/next.rb +90 -0
  97. data/lib/graphql/execution/prepare_object_step.rb +128 -0
  98. data/lib/graphql/execution/runner.rb +410 -0
  99. data/lib/graphql/execution/selections_step.rb +91 -0
  100. data/lib/graphql/execution.rb +8 -4
  101. data/lib/graphql/execution_error.rb +17 -10
  102. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  103. data/lib/graphql/introspection/directive_type.rb +7 -3
  104. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  105. data/lib/graphql/introspection/entry_points.rb +20 -6
  106. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  107. data/lib/graphql/introspection/field_type.rb +13 -5
  108. data/lib/graphql/introspection/input_value_type.rb +21 -13
  109. data/lib/graphql/introspection/schema_type.rb +8 -11
  110. data/lib/graphql/introspection/type_type.rb +64 -28
  111. data/lib/graphql/invalid_name_error.rb +1 -1
  112. data/lib/graphql/invalid_null_error.rb +26 -17
  113. data/lib/graphql/language/block_string.rb +34 -18
  114. data/lib/graphql/language/cache.rb +13 -0
  115. data/lib/graphql/language/comment.rb +18 -0
  116. data/lib/graphql/language/definition_slice.rb +1 -1
  117. data/lib/graphql/language/document_from_schema_definition.rb +90 -61
  118. data/lib/graphql/language/lexer.rb +323 -193
  119. data/lib/graphql/language/nodes.rb +139 -77
  120. data/lib/graphql/language/parser.rb +807 -1985
  121. data/lib/graphql/language/printer.rb +324 -151
  122. data/lib/graphql/language/sanitized_printer.rb +21 -23
  123. data/lib/graphql/language/static_visitor.rb +171 -0
  124. data/lib/graphql/language/visitor.rb +62 -119
  125. data/lib/graphql/language.rb +71 -1
  126. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  127. data/lib/graphql/pagination/array_connection.rb +6 -6
  128. data/lib/graphql/pagination/connection.rb +30 -1
  129. data/lib/graphql/pagination/connections.rb +32 -0
  130. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  131. data/lib/graphql/query/context/scoped_context.rb +101 -0
  132. data/lib/graphql/query/context.rb +88 -144
  133. data/lib/graphql/query/null_context.rb +15 -18
  134. data/lib/graphql/query/partial.rb +194 -0
  135. data/lib/graphql/query/validation_pipeline.rb +4 -4
  136. data/lib/graphql/query/variable_validation_error.rb +1 -1
  137. data/lib/graphql/query/variables.rb +3 -3
  138. data/lib/graphql/query.rb +135 -81
  139. data/lib/graphql/railtie.rb +16 -6
  140. data/lib/graphql/rake_task.rb +3 -12
  141. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  142. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  143. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  144. data/lib/graphql/rubocop.rb +2 -0
  145. data/lib/graphql/runtime_error.rb +6 -0
  146. data/lib/graphql/schema/addition.rb +26 -13
  147. data/lib/graphql/schema/always_visible.rb +7 -2
  148. data/lib/graphql/schema/argument.rb +78 -14
  149. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  150. data/lib/graphql/schema/build_from_definition.rb +140 -66
  151. data/lib/graphql/schema/directive/flagged.rb +4 -2
  152. data/lib/graphql/schema/directive/one_of.rb +12 -0
  153. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  154. data/lib/graphql/schema/directive.rb +78 -12
  155. data/lib/graphql/schema/enum.rb +110 -27
  156. data/lib/graphql/schema/enum_value.rb +11 -3
  157. data/lib/graphql/schema/field/connection_extension.rb +4 -51
  158. data/lib/graphql/schema/field/scope_extension.rb +19 -7
  159. data/lib/graphql/schema/field.rb +245 -119
  160. data/lib/graphql/schema/field_extension.rb +12 -9
  161. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  162. data/lib/graphql/schema/input_object.rb +123 -65
  163. data/lib/graphql/schema/interface.rb +60 -16
  164. data/lib/graphql/schema/introspection_system.rb +8 -17
  165. data/lib/graphql/schema/late_bound_type.rb +4 -0
  166. data/lib/graphql/schema/list.rb +8 -4
  167. data/lib/graphql/schema/loader.rb +3 -4
  168. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -12
  169. data/lib/graphql/schema/member/has_arguments.rb +132 -100
  170. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  171. data/lib/graphql/schema/member/has_dataloader.rb +99 -0
  172. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  173. data/lib/graphql/schema/member/has_directives.rb +5 -5
  174. data/lib/graphql/schema/member/has_fields.rb +121 -17
  175. data/lib/graphql/schema/member/has_interfaces.rb +27 -13
  176. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  177. data/lib/graphql/schema/member/has_validators.rb +1 -1
  178. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  179. data/lib/graphql/schema/member/scoped.rb +19 -0
  180. data/lib/graphql/schema/member/type_system_helpers.rb +18 -5
  181. data/lib/graphql/schema/member/validates_input.rb +3 -3
  182. data/lib/graphql/schema/member.rb +6 -0
  183. data/lib/graphql/schema/mutation.rb +7 -0
  184. data/lib/graphql/schema/non_null.rb +1 -1
  185. data/lib/graphql/schema/object.rb +34 -8
  186. data/lib/graphql/schema/printer.rb +9 -7
  187. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  188. data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
  189. data/lib/graphql/schema/resolver.rb +128 -32
  190. data/lib/graphql/schema/scalar.rb +4 -9
  191. data/lib/graphql/schema/subscription.rb +63 -12
  192. data/lib/graphql/schema/timeout.rb +19 -2
  193. data/lib/graphql/schema/type_expression.rb +2 -2
  194. data/lib/graphql/schema/union.rb +2 -2
  195. data/lib/graphql/schema/unique_within_type.rb +1 -1
  196. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  197. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  198. data/lib/graphql/schema/validator.rb +3 -1
  199. data/lib/graphql/schema/visibility/migration.rb +188 -0
  200. data/lib/graphql/schema/visibility/profile.rb +464 -0
  201. data/lib/graphql/schema/visibility/visit.rb +190 -0
  202. data/lib/graphql/schema/visibility.rb +311 -0
  203. data/lib/graphql/schema/warden.rb +275 -103
  204. data/lib/graphql/schema/wrapper.rb +7 -1
  205. data/lib/graphql/schema.rb +954 -212
  206. data/lib/graphql/static_validation/all_rules.rb +3 -3
  207. data/lib/graphql/static_validation/base_visitor.rb +96 -71
  208. data/lib/graphql/static_validation/literal_validator.rb +6 -7
  209. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +2 -2
  210. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +18 -6
  211. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +6 -2
  212. data/lib/graphql/static_validation/rules/directives_are_defined.rb +6 -3
  213. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  214. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +14 -3
  215. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +59 -15
  216. data/lib/graphql/static_validation/rules/fields_will_merge.rb +391 -262
  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 +6 -6
  219. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +15 -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/query_root_exists.rb +1 -1
  225. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +28 -8
  226. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  227. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  228. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  229. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  230. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  231. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  232. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +14 -2
  233. data/lib/graphql/static_validation/validation_context.rb +22 -6
  234. data/lib/graphql/static_validation/validator.rb +9 -1
  235. data/lib/graphql/static_validation.rb +0 -1
  236. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
  237. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  238. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +45 -19
  239. data/lib/graphql/subscriptions/event.rb +22 -4
  240. data/lib/graphql/subscriptions/serialize.rb +3 -1
  241. data/lib/graphql/subscriptions.rb +56 -17
  242. data/lib/graphql/testing/helpers.rb +161 -0
  243. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  244. data/lib/graphql/testing.rb +3 -0
  245. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  246. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  247. data/lib/graphql/tracing/appoptics_trace.rb +11 -3
  248. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  249. data/lib/graphql/tracing/appsignal_trace.rb +32 -55
  250. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  251. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  252. data/lib/graphql/tracing/data_dog_trace.rb +46 -158
  253. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  254. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -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 +156 -0
  258. data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
  259. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  260. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  261. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  262. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  263. data/lib/graphql/tracing/notifications_trace.rb +184 -34
  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 +864 -0
  269. data/lib/graphql/tracing/platform_trace.rb +5 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
  272. data/lib/graphql/tracing/prometheus_trace.rb +72 -68
  273. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  274. data/lib/graphql/tracing/scout_trace.rb +32 -55
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +82 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +33 -41
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +118 -1
  280. data/lib/graphql/tracing.rb +31 -28
  281. data/lib/graphql/type_kinds.rb +2 -1
  282. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  283. data/lib/graphql/types/relay/connection_behaviors.rb +45 -3
  284. data/lib/graphql/types/relay/edge_behaviors.rb +19 -1
  285. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  286. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  287. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  288. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  289. data/lib/graphql/types.rb +18 -10
  290. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  291. data/lib/graphql/unauthorized_error.rb +9 -1
  292. data/lib/graphql/version.rb +1 -1
  293. data/lib/graphql.rb +69 -54
  294. data/readme.md +12 -2
  295. metadata +236 -40
  296. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  297. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  298. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  299. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  300. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  301. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  302. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  303. data/lib/graphql/analysis/ast.rb +0 -81
  304. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  305. data/lib/graphql/backtrace/trace.rb +0 -96
  306. data/lib/graphql/backtrace/tracer.rb +0 -80
  307. data/lib/graphql/deprecation.rb +0 -9
  308. data/lib/graphql/filter.rb +0 -59
  309. data/lib/graphql/language/parser.y +0 -560
  310. data/lib/graphql/language/token.rb +0 -34
  311. data/lib/graphql/schema/base_64_bp.rb +0 -26
  312. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  313. data/lib/graphql/schema/null_mask.rb +0 -11
  314. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  315. data/lib/graphql/static_validation/type_stack.rb +0 -216
  316. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class Finalize
5
+ def initialize(query, data, runner)
6
+ @query = query
7
+ @data = data
8
+ @static_type_at = runner.static_type_at
9
+ @runner = runner
10
+ @current_exec_path = query.path.dup
11
+ @current_result_path = query.path.dup
12
+ @finalizers = runner.finalizers ? runner.finalizers[query] : {}.compare_by_identity
13
+ @finalizers_count = 0
14
+ @finalizers.each do |key, values|
15
+ values.each do |key2, values2|
16
+ case values2
17
+ when Array
18
+ @finalizers_count += values2.size
19
+ else
20
+ @finalizers_count += 1
21
+ end
22
+ end
23
+ end
24
+
25
+ query.context.errors.each do |err|
26
+ err_path = err.path - @current_exec_path
27
+ key = err_path.pop
28
+ targets = [data]
29
+ while (part = err_path.shift)
30
+ targets.map! { |t| t[part] }
31
+ targets.flatten!
32
+ end
33
+
34
+ targets.each_with_index do |target, idx|
35
+ if target.is_a?(Hash)
36
+ if target[key].equal?(err)
37
+ tf = @finalizers[target] ||= {}.compare_by_identity
38
+ tf[key] = err
39
+ @finalizers_count += 1
40
+ elsif (arr = target[key]).is_a?(Array)
41
+ arr.each_with_index do |el, idx|
42
+ if el.equal?(err)
43
+ tf = @finalizers[arr] ||= {}.compare_by_identity
44
+ tf[idx] = err
45
+ @finalizers_count += 1
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def run
55
+ if (selected_operation = @query.selected_operation) && @data
56
+ if @data.is_a?(Hash)
57
+ check_object_result(@data, @query.root_type, selected_operation.selections)
58
+ elsif @data.is_a?(Array)
59
+ check_list_result(@data, @query.root_type, selected_operation.selections)
60
+ elsif @data.is_a?(Finalizer)
61
+ dummy_data = {}
62
+ dummy_key = "__dummy"
63
+ @data.path = @query.path
64
+ @data.finalize_graphql_result(@query, dummy_data, dummy_key)
65
+ dummy_data[dummy_key]
66
+ else
67
+ raise ArgumentError, "Unexpected @data: #{@data.inspect}"
68
+ end
69
+ else
70
+ @data
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def run_finalizers(result_path, finalizer_or_finalizers, result_data, result_key)
77
+ if finalizer_or_finalizers.is_a?(Array)
78
+ finalizer_or_finalizers.each { |f|
79
+ f.path = result_path
80
+ f.finalize_graphql_result(@query, result_data, result_key)
81
+ }
82
+ @finalizers_count -= finalizer_or_finalizers.size
83
+ else
84
+ f = finalizer_or_finalizers
85
+ f.path = result_path
86
+ f.finalize_graphql_result(@query, result_data, result_key)
87
+ @finalizers_count -= 1
88
+ end
89
+ end
90
+
91
+ def finalizers(result_value, key)
92
+ finalizers_for_value = @finalizers[result_value]
93
+ finalizers_for_value && finalizers_for_value[key]
94
+ end
95
+
96
+ def check_object_result(result_h, parent_type, ast_selections)
97
+ if (f = finalizers(result_h, nil))
98
+ run_finalizers(@current_result_path.dup, f, result_h, nil)
99
+ return result_h if @finalizers_count == 0
100
+ end
101
+
102
+ if parent_type.kind.abstract?
103
+ parent_type = @runner.runtime_type_at[result_h]
104
+ end
105
+
106
+ ast_selections.each do |ast_selection|
107
+ case ast_selection
108
+ when Language::Nodes::Field
109
+ key = ast_selection.alias || ast_selection.name
110
+ if (f = finalizers(result_h, key))
111
+ result_value = result_h[key]
112
+ run_finalizers(@current_result_path.dup << key, f, result_h, key)
113
+ new_result_value = result_h.key?(key) ? result_h[key] : :unassigned
114
+ end
115
+ next if !(f || result_h.key?(key))
116
+ begin
117
+ @current_exec_path << key
118
+ @current_result_path << key
119
+
120
+ field_defn = @query.context.types.field(parent_type, ast_selection.name) || raise("Invariant: No field found for #{static_type.to_type_signature}.#{ast_selection.name}")
121
+ result_type = field_defn.type
122
+ if (result_type_non_null = result_type.non_null?)
123
+ result_type = result_type.of_type
124
+ end
125
+
126
+ if !f
127
+ result_value = result_h[key]
128
+ new_result_value = if result_type.list? && result_value
129
+ check_list_result(result_value, result_type.of_type, ast_selection.selections)
130
+ elsif !result_type.kind.leaf? && result_value
131
+ check_object_result(result_value, result_type, ast_selection.selections)
132
+ else
133
+ result_value
134
+ end
135
+ end
136
+
137
+ if new_result_value.nil? && result_type_non_null
138
+ return nil
139
+ elsif :unassigned.equal?(new_result_value)
140
+ # Do nothing
141
+ break if @finalizers_count == 0
142
+ elsif !new_result_value.equal?(result_value)
143
+ result_h[key] = new_result_value
144
+ break if @finalizers_count == 0
145
+ end
146
+ ensure
147
+ @current_exec_path.pop
148
+ @current_result_path.pop
149
+ end
150
+ when Language::Nodes::InlineFragment
151
+ static_type_at_result = @static_type_at[result_h]
152
+ if static_type_at_result && (
153
+ (t = ast_selection.type).nil? ||
154
+ @runner.type_condition_applies?(@query.context, static_type_at_result, t.name)
155
+ )
156
+ result_h = check_object_result(result_h, parent_type, ast_selection.selections)
157
+ end
158
+ when Language::Nodes::FragmentSpread
159
+ fragment_defn = @query.document.definitions.find { |defn| defn.is_a?(Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
160
+ static_type_at_result = @static_type_at[result_h]
161
+ if static_type_at_result && @runner.type_condition_applies?(@query.context, static_type_at_result, fragment_defn.type.name)
162
+ result_h = check_object_result(result_h, parent_type, fragment_defn.selections)
163
+ end
164
+ end
165
+ end
166
+
167
+ result_h
168
+ end
169
+
170
+ def check_list_result(result_arr, inner_type, ast_selections)
171
+ inner_type_non_null = false
172
+ if inner_type.non_null?
173
+ inner_type_non_null = true
174
+ inner_type = inner_type.of_type
175
+ end
176
+
177
+ new_invalid_null = false
178
+
179
+ if (f = finalizers(result_arr, nil))
180
+ run_finalizers(@current_result_path.dup, f, result_arr, nil)
181
+ return result_arr if @finalizers_count == 0
182
+ end
183
+
184
+ result_arr.each_with_index do |result_item, idx|
185
+ @current_result_path << idx
186
+ new_result = if (f = finalizers(result_arr, idx))
187
+ run_finalizers(@current_result_path.dup, f, result_arr, idx)
188
+ result_arr[idx]
189
+ elsif inner_type.list? && result_item
190
+ check_list_result(result_item, inner_type.of_type, ast_selections)
191
+ elsif !inner_type.kind.leaf? && result_item
192
+ check_object_result(result_item, inner_type, ast_selections)
193
+ else
194
+ result_item
195
+ end
196
+
197
+ if new_result.nil? && inner_type_non_null
198
+ new_invalid_null = true
199
+ result_arr[idx] = nil
200
+ break if @finalizers_count == 0
201
+ elsif !new_result.equal?(result_item)
202
+ result_arr[idx] = new_result
203
+ break if @finalizers_count == 0
204
+ end
205
+ ensure
206
+ @current_result_path.pop
207
+ end
208
+
209
+ if new_invalid_null
210
+ nil
211
+ else
212
+ result_arr
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class InputValues
5
+ def initialize(query, runner)
6
+ @query = query
7
+ @runner = runner
8
+ @variable_values = nil
9
+ end
10
+
11
+ def variable_values
12
+ @variable_values ||= begin
13
+ variable_nodes = @query.selected_operation.variables
14
+ if variable_nodes.empty?
15
+ EmptyObjects::EMPTY_HASH
16
+ else
17
+ raw_values = @query.provided_variables
18
+ values = {}
19
+ variable_nodes.each do |var_node|
20
+ var_ast_value = if raw_values.key?(var_node.name)
21
+ raw_values[var_node.name]
22
+ elsif raw_values.key?(sym_name = var_node.name.to_sym)
23
+ raw_values[sym_name]
24
+ elsif !var_node.default_value.nil?
25
+ var_node.default_value
26
+ else
27
+ next
28
+ end
29
+
30
+ var_type = @runner.schema.type_from_ast(var_node.type, context: @query.context)
31
+ values[var_node.name] = variable_value(var_ast_value, var_type)
32
+ end
33
+ values
34
+ end
35
+ end
36
+ end
37
+
38
+ def argument_values(owner_defn, argument_nodes, field_resolve_step)
39
+ arg_defns = @query.types.arguments(owner_defn)
40
+ argument_values = {}
41
+
42
+ arg_defns.each do |argument_definition|
43
+ arg_ruby_key = argument_definition.keyword
44
+ arg_graphql_key = argument_definition.graphql_name
45
+ arg_node = argument_nodes.find { |a| a.name == arg_graphql_key }
46
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
47
+ if argument_definition.default_value?
48
+ arg_value = value_from_ast(argument_definition.default_value, argument_definition.type)
49
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
50
+ end
51
+ else
52
+ arg_value = value_from_ast(arg_node.value, argument_definition.type)
53
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
54
+ end
55
+ end
56
+
57
+ argument_values
58
+ rescue GraphQL::ExecutionError => exec_err
59
+ exec_err
60
+ end
61
+
62
+ private
63
+
64
+ def variable_value(value, type)
65
+ if type.non_null?
66
+ type = type.of_type
67
+ end
68
+
69
+ if value.is_a?(Language::Nodes::Enum)
70
+ value = value.name
71
+ end
72
+
73
+ if value.nil?
74
+ nil
75
+ elsif type.list?
76
+ inner_type = type.of_type
77
+ if value.is_a?(Array)
78
+ value.map { |v| variable_value(v, inner_type) }.freeze
79
+ else
80
+ [variable_value(value, inner_type)].freeze
81
+ end
82
+ elsif type.kind.input_object?
83
+ coerced_obj = {}
84
+
85
+ @query.types.arguments(type).each do |arg|
86
+ arg_key = arg.keyword
87
+ if value.key?(arg.graphql_name)
88
+ arg_value = value[arg.graphql_name]
89
+ elsif value.key?(sym_name = arg.graphql_name.to_sym)
90
+ arg_value = value[sym_name]
91
+ elsif arg.default_value?
92
+ coerced_obj[arg_key] = arg.default_value
93
+ next
94
+ else
95
+ next
96
+ end
97
+
98
+ coerced_obj[arg_key] = variable_value(arg_value, arg.type)
99
+ end
100
+
101
+ coerced_obj
102
+ elsif type.kind.leaf?
103
+ type.coerce_input(value, @query.context)
104
+ else
105
+ raise GraphQL::Error, "Unexpected input type: #{type.graphql_name}."
106
+ end
107
+ end
108
+
109
+ def argument_value(argument_values, argument_key, argument_definition, arg_value, override_type, field_resolve_step)
110
+ treat_as_type = override_type || argument_definition.type
111
+ if treat_as_type.non_null?
112
+ treat_as_type = treat_as_type.of_type
113
+ end
114
+
115
+ if treat_as_type.kind.list? && !arg_value.nil?
116
+ inner_t = treat_as_type.unwrap
117
+ arg_value = if arg_value.is_a?(Array)
118
+ values = Array.new(arg_value.size)
119
+ arg_value.each_with_index { |inner_v, idx| argument_value(values, idx, argument_definition, inner_v, inner_t, field_resolve_step)}
120
+ values
121
+ else
122
+ values = [nil]
123
+ argument_value(values, 0, argument_definition, arg_value, inner_t, field_resolve_step)
124
+ values
125
+ end
126
+ end
127
+
128
+ if arg_value && treat_as_type.kind.input_object?
129
+ arg_defns = @query.types.arguments(treat_as_type)
130
+ new_arg_value = {}
131
+ arg_defns.each do |inner_arg_defn|
132
+ inner_arg_key = inner_arg_defn.keyword
133
+ if arg_value.is_a?(Hash)
134
+ if arg_value.key?(inner_arg_key)
135
+ inner_arg_value = arg_value[inner_arg_key]
136
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
137
+ end
138
+ else
139
+ inner_arg_name = inner_arg_defn.graphql_name
140
+ inner_arg_value = arg_value.arguments.find { |a| a.name == inner_arg_name } # rubocop:disable Development/ContextIsPassedCop
141
+ if inner_arg_value
142
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
143
+ end
144
+ end
145
+ end
146
+ arg_value = treat_as_type.new(nil, ruby_kwargs: new_arg_value, context: @query.context, defaults_used: nil)
147
+ end
148
+
149
+ if override_type.nil? # only on root arguments, not list elements
150
+ arg_value = begin
151
+ argument_definition.prepare_value(nil, arg_value, context: @query.context)
152
+ rescue StandardError => err
153
+ @runner.schema.handle_or_reraise(@query.context, err)
154
+ end
155
+ end
156
+
157
+ if field_resolve_step && arg_value && override_type.nil? && argument_definition.loads
158
+ field_defn = field_resolve_step.field_definition
159
+ load_receiver = if (r = field_defn.resolver)
160
+ r.new(field: field_defn, context: @query.context, object: nil)
161
+ else
162
+ field_defn
163
+ end
164
+ ps = field_resolve_step.pending_steps ||= []
165
+
166
+ if argument_definition.type.list?
167
+ results = Array.new(arg_value.size, nil)
168
+ argument_values[argument_key] = results
169
+ arg_value.each_with_index do |inner_v, idx|
170
+ loads_step = LoadArgumentStep.new(
171
+ field_resolve_step: field_resolve_step,
172
+ load_receiver: load_receiver,
173
+ argument_value: inner_v,
174
+ argument_definition: argument_definition,
175
+ arguments: results,
176
+ argument_key: idx,
177
+ )
178
+ ps.push(loads_step)
179
+ @runner.add_step(loads_step)
180
+ end
181
+ else
182
+ loads_step = LoadArgumentStep.new(
183
+ field_resolve_step: field_resolve_step,
184
+ load_receiver: load_receiver,
185
+ argument_value: arg_value,
186
+ argument_definition: argument_definition,
187
+ arguments: argument_values,
188
+ argument_key: argument_key,
189
+ )
190
+ ps.push(loads_step)
191
+ @runner.add_step(loads_step)
192
+ end
193
+ else
194
+ argument_values[argument_key] = arg_value
195
+ end
196
+ nil
197
+ end
198
+
199
+ def value_from_ast(value_node, type)
200
+ if type.non_null?
201
+ type = type.of_type
202
+ end
203
+
204
+ if value_node.nil?
205
+ nil
206
+ elsif value_node.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
207
+ variable_values[value_node.name]
208
+ elsif value_node.is_a?(GraphQL::Language::Nodes::NullValue)
209
+ nil
210
+ elsif type.list?
211
+ inner_type = type.of_type
212
+ if value_node.is_a?(Array)
213
+ coerced_items = value_node.map do |inner_value_node|
214
+ value_from_ast(inner_value_node, inner_type)
215
+ end
216
+ coerced_items.freeze
217
+ else
218
+ item_value = value_from_ast(value_node, inner_type)
219
+ [item_value].freeze
220
+ end
221
+
222
+ elsif type.kind.input_object?
223
+ coerced_obj = {}
224
+ arg_nodes_by_name = value_node.arguments.each_with_object({}) do |arg_node, acc| # rubocop:disable Development/ContextIsPassedCop
225
+ acc[arg_node.name] = arg_node
226
+ end
227
+
228
+ @query.types.arguments(type).each do |arg|
229
+ arg_node = arg_nodes_by_name[arg.graphql_name]
230
+ arg_key = arg.keyword
231
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
232
+ if arg.default_value?
233
+ coerced_obj[arg_key] = arg.default_value
234
+ end
235
+ next
236
+ end
237
+
238
+ arg_value = value_from_ast(arg_node.value, arg.type)
239
+ coerced_obj[arg_key] = arg_value
240
+ end
241
+
242
+ coerced_obj
243
+ elsif type.kind.leaf?
244
+ if type.kind.enum?
245
+ if value_node.is_a?(GraphQL::Language::Nodes::Enum)
246
+ value_node = value_node.name
247
+ end
248
+ end
249
+
250
+ begin
251
+ type.coerce_input(value_node, @query.context)
252
+ rescue GraphQL::UnauthorizedEnumValueError => enum_err
253
+ @runner.schema.unauthorized_object(enum_err)
254
+ end
255
+ else
256
+ raise "Unexpected input type: #{type.to_type_signature}."
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -6,15 +6,19 @@ module GraphQL
6
6
  # A container for metadata regarding arguments present in a GraphQL query.
7
7
  # @see Interpreter::Arguments#argument_values for a hash of these objects.
8
8
  class ArgumentValue
9
- def initialize(definition:, value:, default_used:)
9
+ def initialize(definition:, value:, original_value:, default_used:)
10
10
  @definition = definition
11
11
  @value = value
12
+ @original_value = original_value
12
13
  @default_used = default_used
13
14
  end
14
15
 
15
16
  # @return [Object] The Ruby-ready value for this Argument
16
17
  attr_reader :value
17
18
 
19
+ # @return [Object] The value of this argument _before_ `prepare` is applied.
20
+ attr_reader :original_value
21
+
18
22
  # @return [GraphQL::Schema::Argument] The definition instance for this argument
19
23
  attr_reader :definition
20
24
 
@@ -8,22 +8,17 @@ module GraphQL
8
8
  @query = query
9
9
  @dataloader = query.context.dataloader
10
10
  @storage = Hash.new do |h, argument_owner|
11
- args_by_parent = if argument_owner.arguments_statically_coercible?
11
+ h[argument_owner] = if argument_owner.arguments_statically_coercible?
12
12
  shared_values_cache = {}
13
13
  Hash.new do |h2, ignored_parent_object|
14
14
  h2[ignored_parent_object] = shared_values_cache
15
- end
15
+ end.compare_by_identity
16
16
  else
17
17
  Hash.new do |h2, parent_object|
18
- args_by_node = {}
19
- args_by_node.compare_by_identity
20
- h2[parent_object] = args_by_node
21
- end
18
+ h2[parent_object] = {}.compare_by_identity
19
+ end.compare_by_identity
22
20
  end
23
- args_by_parent.compare_by_identity
24
- h[argument_owner] = args_by_parent
25
- end
26
- @storage.compare_by_identity
21
+ end.compare_by_identity
27
22
  end
28
23
 
29
24
  def fetch(ast_node, argument_owner, parent_object)
@@ -5,6 +5,12 @@ module GraphQL
5
5
  class Interpreter
6
6
  # Wrapper for raw values
7
7
  class RawValue
8
+ include GraphQL::Execution::Finalizer
9
+
10
+ def finalize_graphql_result(query, result_data, result_key)
11
+ result_data[result_key] = @object
12
+ end
13
+
8
14
  def initialize(obj = nil)
9
15
  @object = obj
10
16
  end
@@ -6,22 +6,31 @@ module GraphQL
6
6
  module Resolve
7
7
  # Continue field results in `results` until there's nothing else to continue.
8
8
  # @return [void]
9
+ # @deprecated Call `dataloader.run` instead
9
10
  def self.resolve_all(results, dataloader)
11
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
10
12
  dataloader.append_job { resolve(results, dataloader) }
11
13
  nil
12
14
  end
13
15
 
16
+ # @deprecated Call `dataloader.run` instead
14
17
  def self.resolve_each_depth(lazies_at_depth, dataloader)
15
- depths = lazies_at_depth.keys
16
- depths.sort!
17
- next_depth = depths.first
18
- if next_depth
19
- lazies = lazies_at_depth[next_depth]
20
- lazies_at_depth.delete(next_depth)
21
- if lazies.any?
22
- dataloader.append_job {
23
- lazies.each(&:value) # resolve these Lazy instances
24
- }
18
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
19
+
20
+ smallest_depth = nil
21
+ lazies_at_depth.each_key do |depth_key|
22
+ smallest_depth ||= depth_key
23
+ if depth_key < smallest_depth
24
+ smallest_depth = depth_key
25
+ end
26
+ end
27
+
28
+ if smallest_depth
29
+ lazies = lazies_at_depth.delete(smallest_depth)
30
+ if !lazies.empty?
31
+ lazies.each do |l|
32
+ dataloader.append_job { l.value }
33
+ end
25
34
  # Run lazies _and_ dataloader, see if more are enqueued
26
35
  dataloader.run
27
36
  resolve_each_depth(lazies_at_depth, dataloader)
@@ -30,20 +39,9 @@ module GraphQL
30
39
  nil
31
40
  end
32
41
 
33
- # After getting `results` back from an interpreter evaluation,
34
- # continue it until you get a response-ready Ruby value.
35
- #
36
- # `results` is one level of _depth_ of a query or multiplex.
37
- #
38
- # Resolve all lazy values in that depth before moving on
39
- # to the next level.
40
- #
41
- # It's assumed that the lazies will
42
- # return {Lazy} instances if there's more work to be done,
43
- # or return {Hash}/{Array} if the query should be continued.
44
- #
45
- # @return [void]
42
+ # @deprecated Call `dataloader.run` instead
46
43
  def self.resolve(results, dataloader)
44
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
47
45
  # There might be pending jobs here that _will_ write lazies
48
46
  # into the result hash. We should run them out, so we
49
47
  # can be sure that all lazies will be present in the result hashes.
@@ -51,7 +49,7 @@ module GraphQL
51
49
  # these approaches.
52
50
  dataloader.run
53
51
  next_results = []
54
- while results.any?
52
+ while !results.empty?
55
53
  result_value = results.shift
56
54
  if result_value.is_a?(Runtime::GraphQLResultHash) || result_value.is_a?(Hash)
57
55
  results.concat(result_value.values)
@@ -77,7 +75,7 @@ module GraphQL
77
75
  end
78
76
  end
79
77
 
80
- if next_results.any?
78
+ if !next_results.empty?
81
79
  # Any pending data loader jobs may populate the
82
80
  # resutl arrays or result hashes accumulated in
83
81
  # `next_results``. Run those **to completion**