graphql 2.6.12 → 2.6.13

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 (382) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +4 -0
  3. data/lib/generators/graphql/core.rb +1 -0
  4. data/lib/generators/graphql/detailed_trace_generator.rb +1 -0
  5. data/lib/generators/graphql/enum_generator.rb +1 -0
  6. data/lib/generators/graphql/field_extractor.rb +1 -0
  7. data/lib/generators/graphql/input_generator.rb +1 -0
  8. data/lib/generators/graphql/install/mutation_root_generator.rb +1 -0
  9. data/lib/generators/graphql/install_generator.rb +1 -0
  10. data/lib/generators/graphql/interface_generator.rb +1 -0
  11. data/lib/generators/graphql/loader_generator.rb +8 -2
  12. data/lib/generators/graphql/mutation_create_generator.rb +8 -2
  13. data/lib/generators/graphql/mutation_delete_generator.rb +8 -2
  14. data/lib/generators/graphql/mutation_generator.rb +8 -2
  15. data/lib/generators/graphql/mutation_update_generator.rb +8 -2
  16. data/lib/generators/graphql/object_generator.rb +1 -0
  17. data/lib/generators/graphql/orm_mutations_base.rb +8 -2
  18. data/lib/generators/graphql/relay.rb +1 -0
  19. data/lib/generators/graphql/relay_generator.rb +1 -0
  20. data/lib/generators/graphql/scalar_generator.rb +1 -0
  21. data/lib/generators/graphql/type_generator.rb +38 -8
  22. data/lib/generators/graphql/union_generator.rb +1 -0
  23. data/lib/graphql/analysis/analyzer.rb +35 -9
  24. data/lib/graphql/analysis/field_usage.rb +1 -0
  25. data/lib/graphql/analysis/max_query_complexity.rb +2 -1
  26. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  27. data/lib/graphql/analysis/query_complexity.rb +57 -20
  28. data/lib/graphql/analysis/query_depth.rb +17 -12
  29. data/lib/graphql/analysis/visitor.rb +79 -16
  30. data/lib/graphql/analysis.rb +23 -6
  31. data/lib/graphql/analysis_error.rb +1 -0
  32. data/lib/graphql/autoload.rb +30 -7
  33. data/lib/graphql/backtrace/table.rb +21 -5
  34. data/lib/graphql/backtrace/traced_error.rb +8 -3
  35. data/lib/graphql/backtrace.rb +14 -9
  36. data/lib/graphql/coercion_error.rb +1 -0
  37. data/lib/graphql/current.rb +44 -19
  38. data/lib/graphql/dashboard/application_controller.rb +1 -0
  39. data/lib/graphql/dashboard/detailed_traces.rb +1 -0
  40. data/lib/graphql/dashboard/installable.rb +1 -0
  41. data/lib/graphql/dashboard/landings_controller.rb +1 -0
  42. data/lib/graphql/dashboard/limiters.rb +1 -0
  43. data/lib/graphql/dashboard/operation_store.rb +1 -0
  44. data/lib/graphql/dashboard/statics_controller.rb +1 -0
  45. data/lib/graphql/dashboard/subscriptions.rb +1 -0
  46. data/lib/graphql/dashboard.rb +36 -22
  47. data/lib/graphql/dataloader/active_record_association_source.rb +1 -0
  48. data/lib/graphql/dataloader/active_record_source.rb +1 -0
  49. data/lib/graphql/dataloader/async_dataloader.rb +8 -7
  50. data/lib/graphql/dataloader/null_dataloader.rb +4 -3
  51. data/lib/graphql/dataloader/request.rb +8 -2
  52. data/lib/graphql/dataloader/request_all.rb +8 -2
  53. data/lib/graphql/dataloader/source.rb +127 -35
  54. data/lib/graphql/dataloader.rb +91 -42
  55. data/lib/graphql/date_encoding_error.rb +2 -1
  56. data/lib/graphql/dig.rb +12 -3
  57. data/lib/graphql/duration_encoding_error.rb +2 -1
  58. data/lib/graphql/execution/directive_checks.rb +8 -3
  59. data/lib/graphql/execution/errors.rb +20 -6
  60. data/lib/graphql/execution/field_resolve_step.rb +22 -6
  61. data/lib/graphql/execution/finalize.rb +12 -6
  62. data/lib/graphql/execution/input_values.rb +2 -1
  63. data/lib/graphql/execution/interpreter/argument_value.rb +17 -5
  64. data/lib/graphql/execution/interpreter/arguments.rb +24 -9
  65. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -1
  66. data/lib/graphql/execution/interpreter/execution_errors.rb +1 -0
  67. data/lib/graphql/execution/interpreter/handles_raw_value.rb +1 -0
  68. data/lib/graphql/execution/interpreter/resolve.rb +18 -8
  69. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +4 -1
  70. data/lib/graphql/execution/interpreter/runtime.rb +66 -23
  71. data/lib/graphql/execution/interpreter.rb +15 -6
  72. data/lib/graphql/execution/lazy/lazy_method_map.rb +21 -8
  73. data/lib/graphql/execution/lazy.rb +34 -10
  74. data/lib/graphql/execution/load_argument_step.rb +1 -0
  75. data/lib/graphql/execution/lookahead.rb +137 -54
  76. data/lib/graphql/execution/multiplex.rb +4 -4
  77. data/lib/graphql/execution/next.rb +7 -0
  78. data/lib/graphql/execution/prepare_object_step.rb +1 -0
  79. data/lib/graphql/execution/resolve_type_step.rb +2 -1
  80. data/lib/graphql/execution/runner.rb +9 -3
  81. data/lib/graphql/execution/selections_step.rb +3 -2
  82. data/lib/graphql/execution.rb +2 -2
  83. data/lib/graphql/execution_error.rb +19 -10
  84. data/lib/graphql/float_decoding_error.rb +1 -0
  85. data/lib/graphql/float_encoding_error.rb +7 -2
  86. data/lib/graphql/integer_decoding_error.rb +2 -1
  87. data/lib/graphql/integer_encoding_error.rb +8 -3
  88. data/lib/graphql/introspection/base_object.rb +3 -1
  89. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  90. data/lib/graphql/introspection/directive_type.rb +1 -0
  91. data/lib/graphql/introspection/dynamic_fields.rb +1 -0
  92. data/lib/graphql/introspection/entry_points.rb +1 -0
  93. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  94. data/lib/graphql/introspection/field_type.rb +1 -0
  95. data/lib/graphql/introspection/input_value_type.rb +1 -0
  96. data/lib/graphql/introspection/introspection_query.rb +1 -0
  97. data/lib/graphql/introspection/schema_type.rb +1 -0
  98. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  99. data/lib/graphql/introspection/type_type.rb +1 -0
  100. data/lib/graphql/introspection.rb +1 -0
  101. data/lib/graphql/invalid_name_error.rb +1 -0
  102. data/lib/graphql/invalid_null_error.rb +19 -6
  103. data/lib/graphql/language/block_string.rb +2 -1
  104. data/lib/graphql/language/cache.rb +10 -4
  105. data/lib/graphql/language/comment.rb +1 -0
  106. data/lib/graphql/language/definition_slice.rb +1 -0
  107. data/lib/graphql/language/document_from_schema_definition.rb +9 -10
  108. data/lib/graphql/language/generation.rb +23 -9
  109. data/lib/graphql/language/lexer.rb +5 -0
  110. data/lib/graphql/language/nodes.rb +2094 -419
  111. data/lib/graphql/language/parser.rb +17 -11
  112. data/lib/graphql/language/printer.rb +31 -16
  113. data/lib/graphql/language/sanitized_printer.rb +16 -5
  114. data/lib/graphql/language/static_visitor.rb +19 -4
  115. data/lib/graphql/language/visitor.rb +51 -29
  116. data/lib/graphql/language.rb +13 -7
  117. data/lib/graphql/load_application_object_failed_error.rb +14 -5
  118. data/lib/graphql/name_validator.rb +1 -0
  119. data/lib/graphql/pagination/active_record_relation_connection.rb +1 -0
  120. data/lib/graphql/pagination/array_connection.rb +20 -6
  121. data/lib/graphql/pagination/connection.rb +178 -48
  122. data/lib/graphql/pagination/connections.rb +21 -14
  123. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -0
  124. data/lib/graphql/pagination/relation_connection.rb +118 -21
  125. data/lib/graphql/pagination/sequel_dataset_connection.rb +1 -0
  126. data/lib/graphql/pagination.rb +1 -0
  127. data/lib/graphql/parse_error.rb +1 -0
  128. data/lib/graphql/query/context/scoped_context.rb +2 -1
  129. data/lib/graphql/query/context.rb +106 -35
  130. data/lib/graphql/query/fingerprint.rb +15 -7
  131. data/lib/graphql/query/input_validation_result.rb +1 -0
  132. data/lib/graphql/query/null_context.rb +1 -0
  133. data/lib/graphql/query/partial.rb +28 -15
  134. data/lib/graphql/query/result.rb +15 -5
  135. data/lib/graphql/query/validation_pipeline.rb +16 -6
  136. data/lib/graphql/query/variable_validation_error.rb +1 -0
  137. data/lib/graphql/query/variables.rb +4 -1
  138. data/lib/graphql/query.rb +193 -49
  139. data/lib/graphql/railtie.rb +7 -3
  140. data/lib/graphql/rake_task/validate.rb +72 -17
  141. data/lib/graphql/rake_task.rb +55 -23
  142. data/lib/graphql/relay/range_add.rb +32 -21
  143. data/lib/graphql/relay.rb +1 -0
  144. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -0
  145. data/lib/graphql/rubocop/graphql/default_null_true.rb +9 -6
  146. data/lib/graphql/rubocop/graphql/default_required_true.rb +9 -6
  147. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +12 -8
  148. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +9 -5
  149. data/lib/graphql/rubocop.rb +1 -0
  150. data/lib/graphql/runtime_error.rb +1 -0
  151. data/lib/graphql/runtime_type_error.rb +1 -0
  152. data/lib/graphql/schema/addition.rb +18 -6
  153. data/lib/graphql/schema/always_visible.rb +1 -0
  154. data/lib/graphql/schema/argument.rb +265 -42
  155. data/lib/graphql/schema/base_64_encoder.rb +2 -2
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  158. data/lib/graphql/schema/build_from_definition.rb +94 -27
  159. data/lib/graphql/schema/built_in_types.rb +1 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +1 -0
  161. data/lib/graphql/schema/directive/feature.rb +39 -22
  162. data/lib/graphql/schema/directive/flagged.rb +6 -1
  163. data/lib/graphql/schema/directive/include.rb +1 -0
  164. data/lib/graphql/schema/directive/one_of.rb +1 -0
  165. data/lib/graphql/schema/directive/skip.rb +1 -0
  166. data/lib/graphql/schema/directive/specified_by.rb +1 -0
  167. data/lib/graphql/schema/directive/transform.rb +17 -8
  168. data/lib/graphql/schema/directive.rb +12 -7
  169. data/lib/graphql/schema/enum.rb +99 -38
  170. data/lib/graphql/schema/enum_value.rb +21 -13
  171. data/lib/graphql/schema/field/connection_extension.rb +10 -2
  172. data/lib/graphql/schema/field/scope_extension.rb +1 -0
  173. data/lib/graphql/schema/field.rb +621 -109
  174. data/lib/graphql/schema/field_extension.rb +89 -34
  175. data/lib/graphql/schema/find_inherited_value.rb +5 -3
  176. data/lib/graphql/schema/finder.rb +22 -8
  177. data/lib/graphql/schema/has_single_input_argument.rb +39 -6
  178. data/lib/graphql/schema/input_object.rb +40 -13
  179. data/lib/graphql/schema/interface.rb +33 -17
  180. data/lib/graphql/schema/introspection_system.rb +7 -3
  181. data/lib/graphql/schema/late_bound_type.rb +2 -2
  182. data/lib/graphql/schema/list.rb +15 -4
  183. data/lib/graphql/schema/loader.rb +23 -12
  184. data/lib/graphql/schema/member/base_dsl_methods.rb +58 -12
  185. data/lib/graphql/schema/member/build_type.rb +16 -5
  186. data/lib/graphql/schema/member/graphql_type_names.rb +10 -6
  187. data/lib/graphql/schema/member/has_arguments.rb +115 -48
  188. data/lib/graphql/schema/member/has_ast_node.rb +1 -0
  189. data/lib/graphql/schema/member/has_authorization.rb +5 -0
  190. data/lib/graphql/schema/member/has_dataloader.rb +91 -34
  191. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -2
  192. data/lib/graphql/schema/member/has_directives.rb +38 -10
  193. data/lib/graphql/schema/member/has_fields.rb +151 -70
  194. data/lib/graphql/schema/member/has_interfaces.rb +10 -2
  195. data/lib/graphql/schema/member/has_path.rb +14 -5
  196. data/lib/graphql/schema/member/has_unresolved_type_error.rb +1 -0
  197. data/lib/graphql/schema/member/has_validators.rb +19 -4
  198. data/lib/graphql/schema/member/relay_shortcuts.rb +10 -2
  199. data/lib/graphql/schema/member/scoped.rb +14 -3
  200. data/lib/graphql/schema/member/type_system_helpers.rb +36 -6
  201. data/lib/graphql/schema/member/validates_input.rb +1 -0
  202. data/lib/graphql/schema/member.rb +9 -2
  203. data/lib/graphql/schema/mutation.rb +50 -46
  204. data/lib/graphql/schema/non_null.rb +21 -5
  205. data/lib/graphql/schema/object.rb +33 -12
  206. data/lib/graphql/schema/printer.rb +52 -31
  207. data/lib/graphql/schema/ractor_shareable.rb +6 -2
  208. data/lib/graphql/schema/relay_classic_mutation.rb +3 -3
  209. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -7
  210. data/lib/graphql/schema/resolver.rb +156 -45
  211. data/lib/graphql/schema/scalar.rb +1 -0
  212. data/lib/graphql/schema/subscription.rb +67 -28
  213. data/lib/graphql/schema/timeout.rb +65 -25
  214. data/lib/graphql/schema/type_expression.rb +14 -5
  215. data/lib/graphql/schema/type_membership.rb +29 -10
  216. data/lib/graphql/schema/union.rb +4 -2
  217. data/lib/graphql/schema/unique_within_type.rb +24 -5
  218. data/lib/graphql/schema/validator/all_validator.rb +17 -9
  219. data/lib/graphql/schema/validator/allow_blank_validator.rb +8 -2
  220. data/lib/graphql/schema/validator/allow_null_validator.rb +8 -2
  221. data/lib/graphql/schema/validator/exclusion_validator.rb +14 -5
  222. data/lib/graphql/schema/validator/format_validator.rb +21 -10
  223. data/lib/graphql/schema/validator/inclusion_validator.rb +15 -6
  224. data/lib/graphql/schema/validator/length_validator.rb +23 -12
  225. data/lib/graphql/schema/validator/numericality_validator.rb +29 -16
  226. data/lib/graphql/schema/validator/required_validator.rb +45 -31
  227. data/lib/graphql/schema/validator.rb +89 -25
  228. data/lib/graphql/schema/visibility/migration.rb +14 -7
  229. data/lib/graphql/schema/visibility/profile.rb +20 -17
  230. data/lib/graphql/schema/visibility/visit.rb +12 -10
  231. data/lib/graphql/schema/visibility.rb +24 -20
  232. data/lib/graphql/schema/warden.rb +117 -31
  233. data/lib/graphql/schema/wrapper.rb +4 -1
  234. data/lib/graphql/schema.rb +1046 -300
  235. data/lib/graphql/static_validation/all_rules.rb +2 -1
  236. data/lib/graphql/static_validation/base_visitor.rb +48 -8
  237. data/lib/graphql/static_validation/definition_dependencies.rb +27 -7
  238. data/lib/graphql/static_validation/error.rb +3 -0
  239. data/lib/graphql/static_validation/interpreter_visitor.rb +1 -0
  240. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  241. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -0
  242. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +1 -0
  243. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +3 -0
  244. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +1 -0
  245. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -0
  246. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +1 -0
  247. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -0
  248. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +1 -0
  249. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +3 -0
  250. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +1 -0
  251. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -0
  252. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +1 -0
  253. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +9 -1
  254. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +1 -0
  255. data/lib/graphql/static_validation/rules/fields_will_merge.rb +295 -134
  256. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +14 -2
  257. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +3 -0
  258. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +1 -0
  259. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -0
  260. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +1 -0
  261. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +3 -0
  262. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +1 -0
  263. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +3 -0
  264. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +1 -0
  265. data/lib/graphql/static_validation/rules/fragments_are_named.rb +3 -0
  266. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +1 -0
  267. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +3 -0
  268. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +1 -0
  269. data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -0
  270. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +1 -0
  271. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +3 -0
  272. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +1 -0
  273. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +3 -0
  274. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +1 -0
  275. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +3 -0
  276. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +1 -0
  277. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +1 -0
  278. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +4 -0
  279. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +1 -0
  280. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +3 -0
  281. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +1 -0
  282. data/lib/graphql/static_validation/rules/query_root_exists.rb +3 -0
  283. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +1 -0
  284. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -1
  285. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +1 -0
  286. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -0
  287. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +1 -0
  288. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +4 -1
  289. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +1 -0
  290. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +3 -0
  291. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +1 -0
  292. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -0
  293. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +1 -0
  294. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +3 -0
  295. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +1 -0
  296. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +207 -51
  297. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +1 -0
  298. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +3 -0
  299. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +1 -0
  300. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -3
  301. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +1 -0
  302. data/lib/graphql/static_validation/validation_context.rb +3 -2
  303. data/lib/graphql/static_validation/validation_timeout_error.rb +1 -0
  304. data/lib/graphql/static_validation/validator.rb +41 -16
  305. data/lib/graphql/static_validation.rb +1 -0
  306. data/lib/graphql/string_encoding_error.rb +1 -0
  307. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +85 -65
  308. data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
  309. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +1 -0
  310. data/lib/graphql/subscriptions/event.rb +25 -6
  311. data/lib/graphql/subscriptions/serialize.rb +58 -19
  312. data/lib/graphql/subscriptions.rb +172 -46
  313. data/lib/graphql/testing/helpers.rb +17 -4
  314. data/lib/graphql/testing/mock_action_cable.rb +55 -33
  315. data/lib/graphql/testing.rb +1 -0
  316. data/lib/graphql/tracing/active_support_notifications_trace.rb +17 -9
  317. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  318. data/lib/graphql/tracing/appoptics_trace.rb +2 -1
  319. data/lib/graphql/tracing/appoptics_tracing.rb +2 -1
  320. data/lib/graphql/tracing/appsignal_trace.rb +16 -7
  321. data/lib/graphql/tracing/appsignal_tracing.rb +7 -3
  322. data/lib/graphql/tracing/call_legacy_tracers.rb +1 -0
  323. data/lib/graphql/tracing/data_dog_trace.rb +17 -6
  324. data/lib/graphql/tracing/data_dog_tracing.rb +10 -3
  325. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +1 -0
  326. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +1 -0
  327. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +1 -0
  328. data/lib/graphql/tracing/detailed_trace.rb +105 -42
  329. data/lib/graphql/tracing/legacy_hooks_trace.rb +5 -0
  330. data/lib/graphql/tracing/legacy_trace.rb +1 -0
  331. data/lib/graphql/tracing/monitor_trace.rb +17 -11
  332. data/lib/graphql/tracing/new_relic_trace.rb +17 -8
  333. data/lib/graphql/tracing/new_relic_tracing.rb +7 -3
  334. data/lib/graphql/tracing/notifications_trace.rb +11 -8
  335. data/lib/graphql/tracing/notifications_tracing.rb +23 -7
  336. data/lib/graphql/tracing/null_trace.rb +1 -0
  337. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +1 -0
  338. data/lib/graphql/tracing/perfetto_trace.rb +41 -19
  339. data/lib/graphql/tracing/platform_trace.rb +3 -1
  340. data/lib/graphql/tracing/platform_tracing.rb +16 -7
  341. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +1 -0
  342. data/lib/graphql/tracing/prometheus_trace.rb +22 -13
  343. data/lib/graphql/tracing/prometheus_tracing.rb +1 -0
  344. data/lib/graphql/tracing/scout_trace.rb +10 -4
  345. data/lib/graphql/tracing/scout_tracing.rb +7 -3
  346. data/lib/graphql/tracing/sentry_trace.rb +12 -5
  347. data/lib/graphql/tracing/statsd_trace.rb +12 -6
  348. data/lib/graphql/tracing/statsd_tracing.rb +7 -1
  349. data/lib/graphql/tracing/trace.rb +231 -58
  350. data/lib/graphql/tracing.rb +25 -9
  351. data/lib/graphql/type_kinds.rb +2 -1
  352. data/lib/graphql/types/big_int.rb +1 -0
  353. data/lib/graphql/types/boolean.rb +1 -0
  354. data/lib/graphql/types/float.rb +1 -0
  355. data/lib/graphql/types/id.rb +1 -0
  356. data/lib/graphql/types/int.rb +2 -1
  357. data/lib/graphql/types/iso_8601_date.rb +21 -4
  358. data/lib/graphql/types/iso_8601_date_time.rb +33 -6
  359. data/lib/graphql/types/iso_8601_duration.rb +42 -9
  360. data/lib/graphql/types/json.rb +1 -0
  361. data/lib/graphql/types/relay/base_connection.rb +38 -32
  362. data/lib/graphql/types/relay/base_edge.rb +15 -9
  363. data/lib/graphql/types/relay/connection_behaviors.rb +19 -3
  364. data/lib/graphql/types/relay/edge_behaviors.rb +17 -4
  365. data/lib/graphql/types/relay/has_node_field.rb +6 -1
  366. data/lib/graphql/types/relay/has_nodes_field.rb +6 -1
  367. data/lib/graphql/types/relay/node.rb +1 -0
  368. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  369. data/lib/graphql/types/relay/page_info.rb +1 -0
  370. data/lib/graphql/types/relay/page_info_behaviors.rb +1 -0
  371. data/lib/graphql/types/relay.rb +4 -3
  372. data/lib/graphql/types/string.rb +1 -0
  373. data/lib/graphql/types.rb +1 -0
  374. data/lib/graphql/unauthorized_enum_value_error.rb +4 -1
  375. data/lib/graphql/unauthorized_error.rb +11 -4
  376. data/lib/graphql/unauthorized_field_error.rb +4 -1
  377. data/lib/graphql/unresolved_type_error.rb +16 -5
  378. data/lib/graphql/version.rb +2 -1
  379. data/lib/graphql.rb +37 -9
  380. data/readme.md +1 -1
  381. metadata +89 -5
  382. data/.yardopts +0 -5
data/lib/graphql/query.rb CHANGED
@@ -1,7 +1,42 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  module GraphQL
4
- # A combination of query string and {Schema} instance which can be reduced to a {#result}.
5
+ # A combination of query string and [Schema](rdoc-ref:GraphQL::Schema) instance which can be reduced to a [result](rdoc-ref:#result).
6
+ #
7
+ # The API-specific portions of `guides/queries/executing_queries.md` were
8
+ # migrated to `Schema#execute`, `Schema#multiplex`, and this initializer.
9
+ # Those APIs accept query strings or parsed documents, variables, context,
10
+ # root values, operation names, validation controls, and depth/complexity
11
+ # limits. The guide remains a standalone execution tutorial.
12
+ #
13
+ # ## API-specific portions
14
+ #
15
+ # [GraphQL::Schema.execute](rdoc-ref:GraphQL::Schema.execute) runs one query
16
+ # and [GraphQL::Schema.multiplex](rdoc-ref:GraphQL::Schema.multiplex) runs
17
+ # several queries with shared multiplex-level context. Both delegate to this
18
+ # class, so the following options have the same meaning in each API:
19
+ #
20
+ # - `query` or the positional query string is a GraphQL document to parse.
21
+ # - `document:` accepts an already-parsed
22
+ # [GraphQL::Language::Nodes::Document](rdoc-ref:GraphQL::Language::Nodes::Document);
23
+ # pass one or the other, not both.
24
+ # - `variables:` is a `Hash` of values for `$`-named variables. Keys omit the
25
+ # leading `$`; values may contain nested input objects.
26
+ # - `context:` contains application values made available to field resolvers,
27
+ # schema hooks, and [Query::Context](rdoc-ref:GraphQL::Query::Context).
28
+ # - `root_value:` is passed as `obj` to root-level fields.
29
+ # - `operation_name:` selects which named operation to execute when a document
30
+ # contains more than one operation.
31
+ # - `validate: false` skips static validation. Use this only when the document
32
+ # has already been validated; execution of an invalid document is undefined.
33
+ # - `max_depth:` and `max_complexity:` override the corresponding schema limits
34
+ # for this query. `nil` uses the schema configuration.
35
+ #
36
+ # The [executing queries guide](/queries/executing_queries) keeps examples for
37
+ # variables, context, scoped context, and root values. This class and the
38
+ # `Schema#execute`/`Schema#multiplex` method comments are the source of truth
39
+ # for option names, defaults, and execution behavior.
5
40
  class Query
6
41
  extend Autoload
7
42
  include Tracing::Traceable
@@ -17,7 +52,7 @@ module GraphQL
17
52
  autoload :VariableValidationError, "graphql/query/variable_validation_error"
18
53
  autoload :ValidationPipeline, "graphql/query/validation_pipeline"
19
54
 
20
- # Code shared with {Partial}
55
+ # Code shared with [Partial](rdoc-ref:GraphQL::Query::Partial)
21
56
  module Runnable
22
57
  def after_lazy(value, &block)
23
58
  if !defined?(@runtime_instance)
@@ -32,10 +67,19 @@ module GraphQL
32
67
  end
33
68
 
34
69
  # Node-level cache for calculating arguments. Used during execution and query analysis.
35
- # @param ast_node [GraphQL::Language::Nodes::AbstractNode]
36
- # @param definition [GraphQL::Schema::Field]
37
- # @param parent_object [GraphQL::Schema::Object]
38
- # @return [Hash{Symbol => Object}]
70
+ #
71
+ # **Parameters**
72
+ #
73
+ # - `ast_node` (`GraphQL::Language::Nodes::AbstractNode`)
74
+ # - `definition` (`GraphQL::Schema::Field`)
75
+ # - `parent_object` (`GraphQL::Schema::Object`)
76
+ #
77
+ # **Returns**
78
+ #
79
+ # - `Hash{Symbol => Object}`
80
+ #
81
+ # :call-seq:
82
+ # arguments_for(GraphQL::Language::Nodes::AbstractNode ast_node, GraphQL::Schema::Field definition, GraphQL::Schema::Object parent_object:) -> Hash[Symbol, Object]
39
83
  def arguments_for(ast_node, definition, parent_object: nil)
40
84
  arguments_cache.fetch(ast_node, definition, parent_object)
41
85
  end
@@ -44,8 +88,7 @@ module GraphQL
44
88
  @arguments_cache ||= Execution::Interpreter::ArgumentsCache.new(self)
45
89
  end
46
90
 
47
- # @api private
48
- def handle_or_reraise(err, **kwargs)
91
+ def handle_or_reraise(err, **kwargs) # :nodoc:
49
92
  @schema.handle_or_reraise(context, err, **kwargs)
50
93
  end
51
94
  end
@@ -67,13 +110,22 @@ module GraphQL
67
110
  # The value for root types
68
111
  attr_accessor :root_value
69
112
 
70
- # @return [nil, String] The operation name provided by client or the one inferred from the document. Used to determine which operation to run.
113
+ # **Returns**
114
+ #
115
+ # - `nil, String` — The operation name provided by client or the one inferred from the document. Used to determine which operation to run.
71
116
  attr_accessor :operation_name
72
117
 
73
- # @return [Boolean] if false, static validation is skipped (execution behavior for invalid queries is undefined)
118
+ # **Returns**
119
+ #
120
+ # - `Boolean` — if false, static validation is skipped (execution behavior for invalid queries is undefined)
74
121
  attr_reader :validate
75
122
 
76
- # @param new_validate [Boolean] if false, static validation is skipped. This can't be reasssigned after validation.
123
+ # **Parameters**
124
+ #
125
+ # - `new_validate` (`Boolean`) — if false, static validation is skipped. This can't be reasssigned after validation.
126
+ #
127
+ # :call-seq:
128
+ # validate=(bool new_validate)
77
129
  def validate=(new_validate)
78
130
  if defined?(@validation_pipeline) && @validation_pipeline && @validation_pipeline.has_validated?
79
131
  raise ArgumentError, "Can't reassign Query#validate= after validation has run, remove this assignment."
@@ -82,10 +134,17 @@ module GraphQL
82
134
  end
83
135
  end
84
136
 
85
- # @return [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules.
137
+ # **Returns**
138
+ #
139
+ # - `GraphQL::StaticValidation::Validator` — if present, the query will validate with these rules.
86
140
  attr_reader :static_validator
87
141
 
88
- # @param new_validator [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules. This can't be reasssigned after validation.
142
+ # **Parameters**
143
+ #
144
+ # - `new_validator` (`GraphQL::StaticValidation::Validator`) — if present, the query will validate with these rules. This can't be reasssigned after validation.
145
+ #
146
+ # :call-seq:
147
+ # static_validator=(GraphQL::StaticValidation::Validator new_validator)
89
148
  def static_validator=(new_validator)
90
149
  if defined?(@validation_pipeline) && @validation_pipeline && @validation_pipeline.has_validated?
91
150
  raise ArgumentError, "Can't reassign Query#static_validator= after validation has run, remove this assignment."
@@ -98,7 +157,12 @@ module GraphQL
98
157
 
99
158
  attr_writer :query_string
100
159
 
101
- # @return [GraphQL::Language::Nodes::Document]
160
+ # **Returns**
161
+ #
162
+ # - `GraphQL::Language::Nodes::Document`
163
+ #
164
+ # :call-seq:
165
+ # document() -> GraphQL::Language::Nodes::Document
102
166
  def document
103
167
  # It's ok if this hasn't been assigned yet
104
168
  if @query_string || @document
@@ -112,27 +176,40 @@ module GraphQL
112
176
  "query ..."
113
177
  end
114
178
 
115
- # @return [String, nil] The name of the operation to run (may be inferred)
179
+ # **Returns**
180
+ #
181
+ # - `String, nil` — The name of the operation to run (may be inferred)
182
+ #
183
+ # :call-seq:
184
+ # selected_operation_name() -> String | nil
116
185
  def selected_operation_name
117
186
  return nil unless selected_operation
118
187
  selected_operation.name
119
188
  end
120
189
 
121
- # @return [String, nil] the triggered event, if this query is a subscription update
190
+ # **Returns**
191
+ #
192
+ # - `String, nil` — the triggered event, if this query is a subscription update
122
193
  attr_reader :subscription_topic
123
194
 
124
195
  attr_reader :tracers
125
196
 
126
197
  # Prepare query `query_string` on `schema`
127
- # @param schema [GraphQL::Schema]
128
- # @param query_string [String]
129
- # @param context [#[]] an arbitrary hash of values which you can access in {GraphQL::Field#resolve}
130
- # @param variables [Hash] values for `$variables` in the query
131
- # @param operation_name [String] if the query string contains many operations, this is the one which should be executed
132
- # @param root_value [Object] the object used to resolve fields on the root type
133
- # @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
134
- # @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
135
- # @param visibility_profile [Symbol] Another way to assign `context[:visibility_profile]`
198
+ #
199
+ # **Parameters**
200
+ #
201
+ # - `schema` (`GraphQL::Schema`)
202
+ # - `query_string` (`String`)
203
+ # - `context` (`#[]`) — an arbitrary hash of values which you can access in [Schema::Field#resolve](rdoc-ref:GraphQL::Schema::Field#resolve)
204
+ # - `variables` (`Hash`) — values for `$variables` in the query
205
+ # - `operation_name` (`String`) — if the query string contains many operations, this is the one which should be executed
206
+ # - `root_value` (`Object`) — the object used to resolve fields on the root type
207
+ # - `max_depth` (`Numeric`) — the maximum number of nested selections allowed for this query (falls back to schema-level value)
208
+ # - `max_complexity` (`Numeric`) — the maximum field complexity for this query (falls back to schema-level value)
209
+ # - `visibility_profile` (`Symbol`) — Another way to assign `context[:visibility_profile]`
210
+ #
211
+ # :call-seq:
212
+ # initialize(GraphQL::Schema schema, String query_string, query:, document:, #[] context:, Hash variables:, multiplex:, validate:, static_validator:, Symbol visibility_profile:, subscription_topic:, String operation_name:, Object root_value:, Numeric max_depth:, Numeric max_complexity:, warden:, use_visibility_profile:)
136
213
  def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, multiplex: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
137
214
  # Even if `variables: nil` is passed, use an empty hash for simpler logic
138
215
  variables ||= {}
@@ -216,12 +293,19 @@ module GraphQL
216
293
  @query_string ||= (document ? document.to_query_string : nil)
217
294
  end
218
295
 
219
- # @return [Symbol, nil]
296
+ # **Returns**
297
+ #
298
+ # - `Symbol, nil`
220
299
  attr_reader :visibility_profile
221
300
 
222
301
  attr_accessor :multiplex
223
302
 
224
- # @return [GraphQL::Tracing::Trace]
303
+ # **Returns**
304
+ #
305
+ # - `GraphQL::Tracing::Trace`
306
+ #
307
+ # :call-seq:
308
+ # current_trace() -> GraphQL::Tracing::Trace
225
309
  def current_trace
226
310
  @current_trace ||= context[:trace] || (multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self))
227
311
  end
@@ -231,7 +315,13 @@ module GraphQL
231
315
  end
232
316
 
233
317
  # A lookahead for the root selections of this query
234
- # @return [GraphQL::Execution::Lookahead]
318
+ #
319
+ # **Returns**
320
+ #
321
+ # - `GraphQL::Execution::Lookahead`
322
+ #
323
+ # :call-seq:
324
+ # lookahead() -> GraphQL::Execution::Lookahead
235
325
  def lookahead
236
326
  @lookahead ||= begin
237
327
  if selected_operation.nil?
@@ -242,8 +332,7 @@ module GraphQL
242
332
  end
243
333
  end
244
334
 
245
- # @api private
246
- def result_values=(result_hash)
335
+ def result_values=(result_hash) # :nodoc:
247
336
  if @executed
248
337
  raise "Invariant: Can't reassign result"
249
338
  else
@@ -252,8 +341,7 @@ module GraphQL
252
341
  end
253
342
  end
254
343
 
255
- # @api private
256
- attr_reader :result_values
344
+ attr_reader :result_values # :nodoc:
257
345
 
258
346
  def fragments
259
347
  with_prepared_ast { @fragments }
@@ -272,10 +360,19 @@ module GraphQL
272
360
  # where the path references a field in the AST and the object will be treated
273
361
  # as the return value from that field. Subfields of the field named by `path`
274
362
  # will be executed with `object` as the starting point
275
- # @param partials_hashes [Array<Hash{Symbol => Object}>] Hashes with `path:` and `object:` keys
276
- # @return [Array<GraphQL::Query::Result>]
363
+ #
364
+ # **Parameters**
365
+ #
366
+ # - `partials_hashes` (`Array<Hash{Symbol => Object}>`) — Hashes with `path:` and `object:` keys
367
+ #
368
+ # **Returns**
369
+ #
370
+ # - `Array<GraphQL::Query::Result>`
371
+ #
372
+ # :call-seq:
373
+ # run_partials(Array[Hash[Symbol, Object]] partials_hashes) -> Array[GraphQL::Query::Result]
277
374
  def run_partials(partials_hashes)
278
- partials = partials_hashes.map { |partial_options| Partial.new(query: self, **partial_options) }
375
+ partials = partials_hashes.map { |partial_options| Partial.new(**partial_options, query: self) }
279
376
  if context[:__graphql_execute_next]
280
377
  Execution::Next.run_all(@schema, partials, context: @context)
281
378
  else
@@ -284,7 +381,13 @@ module GraphQL
284
381
  end
285
382
 
286
383
  # Get the result for this query, executing it once
287
- # @return [GraphQL::Query::Result] A Hash-like GraphQL response, with `"data"` and/or `"errors"` keys
384
+ #
385
+ # **Returns**
386
+ #
387
+ # - `GraphQL::Query::Result` — A Hash-like GraphQL response, with `"data"` and/or `"errors"` keys
388
+ #
389
+ # :call-seq:
390
+ # result() -> GraphQL::Query::Result
288
391
  def result
289
392
  if !@executed
290
393
  execution_engine = @schema.default_execution_next ? Execution::Next : Execution::Interpreter
@@ -303,7 +406,13 @@ module GraphQL
303
406
 
304
407
  # This is the operation to run for this query.
305
408
  # If more than one operation is present, it must be named at runtime.
306
- # @return [GraphQL::Language::Nodes::OperationDefinition, nil]
409
+ #
410
+ # **Returns**
411
+ #
412
+ # - `GraphQL::Language::Nodes::OperationDefinition, nil`
413
+ #
414
+ # :call-seq:
415
+ # selected_operation() -> GraphQL::Language::Nodes::OperationDefinition | nil
307
416
  def selected_operation
308
417
  with_prepared_ast { @selected_operation }
309
418
  end
@@ -311,9 +420,14 @@ module GraphQL
311
420
  # Determine the values for variables of this query, using default values
312
421
  # if a value isn't provided at runtime.
313
422
  #
314
- # If some variable is invalid, errors are added to {#validation_errors}.
423
+ # If some variable is invalid, errors are added to the query's validation errors.
424
+ #
425
+ # **Returns**
426
+ #
427
+ # - `GraphQL::Query::Variables` — Variables to apply to this query
315
428
  #
316
- # @return [GraphQL::Query::Variables] Variables to apply to this query
429
+ # :call-seq:
430
+ # variables() -> GraphQL::Query::Variables
317
431
  def variables
318
432
  @variables ||= begin
319
433
  with_prepared_ast {
@@ -329,7 +443,13 @@ module GraphQL
329
443
  # A version of the given query string, with:
330
444
  # - Variables inlined to the query
331
445
  # - Strings replaced with `<REDACTED>`
332
- # @return [String, nil] Returns nil if the query is invalid.
446
+ #
447
+ # **Returns**
448
+ #
449
+ # - `String, nil` — Returns nil if the query is invalid.
450
+ #
451
+ # :call-seq:
452
+ # sanitized_query_string(inline_variables:) -> String | nil
333
453
  def sanitized_query_string(inline_variables: true)
334
454
  with_prepared_ast {
335
455
  schema.sanitized_printer.new(self, inline_variables: inline_variables).sanitized_query_string
@@ -345,19 +465,34 @@ module GraphQL
345
465
  #
346
466
  # This fingerprint can be used to track runs of the same operation-variables combination over time.
347
467
  #
348
- # @see operation_fingerprint
349
- # @see variables_fingerprint
350
- # @return [String] An opaque hash identifying this operation-variables combination
468
+ # See `operation_fingerprint` and `variables_fingerprint` for the components.
469
+ #
470
+ # **Returns**
471
+ #
472
+ # - `String` — An opaque hash identifying this operation-variables combination
473
+ #
474
+ # :call-seq:
475
+ # fingerprint() -> String
351
476
  def fingerprint
352
477
  @fingerprint ||= "#{operation_fingerprint}/#{variables_fingerprint}"
353
478
  end
354
479
 
355
- # @return [String] An opaque hash for identifying this query's given query string and selected operation
480
+ # **Returns**
481
+ #
482
+ # - `String` — An opaque hash for identifying this query's given query string and selected operation
483
+ #
484
+ # :call-seq:
485
+ # operation_fingerprint() -> String
356
486
  def operation_fingerprint
357
487
  @operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string || "")}"
358
488
  end
359
489
 
360
- # @return [String] An opaque hash for identifying this query's given a variable values (not including defaults)
490
+ # **Returns**
491
+ #
492
+ # - `String` — An opaque hash for identifying this query's given a variable values (not including defaults)
493
+ #
494
+ # :call-seq:
495
+ # variables_fingerprint() -> String
361
496
  def variables_fingerprint
362
497
  @variables_fingerprint ||= "#{provided_variables.size}/#{Fingerprint.generate(provided_variables.to_json)}"
363
498
  end
@@ -411,10 +546,19 @@ module GraphQL
411
546
  @visibility_profile || warden.visibility_profile
412
547
  end
413
548
 
414
- # @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
415
- # @param value [Object] Any runtime value
416
- # @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
417
- # @see {#possible_types} to apply filtering from `only` / `except`
549
+ # See [possible_types](rdoc-ref:#possible_types) to apply filtering from `only` / `except`
550
+ #
551
+ # **Parameters**
552
+ #
553
+ # - `abstract_type` (`GraphQL::UnionType, GraphQL::InterfaceType`)
554
+ # - `value` (`Object`) — Any runtime value
555
+ #
556
+ # **Returns**
557
+ #
558
+ # - `GraphQL::ObjectType, nil` — The runtime type of `value` from [Schema.resolve_type](rdoc-ref:GraphQL::Schema::resolve_type)
559
+ #
560
+ # :call-seq:
561
+ # resolve_type(GraphQL::UnionType | GraphQL::InterfaceType abstract_type, Object value) -> GraphQL::ObjectType | nil
418
562
  def resolve_type(abstract_type, value = NOT_CONFIGURED)
419
563
  if value.is_a?(Symbol) && value == NOT_CONFIGURED
420
564
  # Old method signature
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  module GraphQL
4
- # Support {GraphQL::Parser::Cache} and {GraphQL.eager_load!}
5
+ # Support [GraphQL::Language::Cache](rdoc-ref:GraphQL::Language::Cache) and [GraphQL.eager_load!](rdoc-ref:GraphQL.eager_load!)
5
6
  #
6
- # @example Enable the parser cache with default directory
7
+ # **Examples**
7
8
  #
8
- # config.graphql.parser_cache = true
9
+ # **Example: Enable the parser cache with default directory**
9
10
  #
11
+ # ```ruby
12
+ # config.graphql.parser_cache = true
13
+ # ```
10
14
  class Railtie < Rails::Railtie
11
15
  config.graphql = ActiveSupport::OrderedOptions.new
12
16
  config.graphql.parser_cache = false
@@ -1,21 +1,83 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
3
+ require "digest/sha2"
4
+ require "net/http"
5
+ require "erb"
2
6
 
3
7
  module GraphQL
4
8
  class RakeTask
5
9
  extend Rake::DSL
6
10
 
11
+ # Helpers for `graphql:pro:validate`.
12
+ # Credentials are never passed to a subprocess, so they can't leak into the process list or logs.
13
+ module Validate
14
+ CREDENTIALS_PATTERN = /\A[a-z0-9]{11}:[a-z0-9]{11}\z/
15
+ DIGEST_PATTERN = /\A\h{128}\z/
16
+
17
+ module_function
18
+
19
+ # Returns a normalized version string, or `nil` if `version` isn't a valid gem version.
20
+ def normalize_version(version)
21
+ # `Gem::Version.correct?` accepts `nil` and `""`, so check those first
22
+ if !version.is_a?(String) || version.strip.empty? || !Gem::Version.correct?(version)
23
+ nil
24
+ else
25
+ # Strips surrounding whitespace, leaving only `[0-9a-zA-Z.]`
26
+ Gem::Version.new(version).to_s
27
+ end
28
+ end
29
+
30
+ # Returns `user:pass` for gems.graphql.pro, or `nil` if it isn't configured.
31
+ def credentials
32
+ creds = if defined?(Bundler) && Bundler.respond_to?(:settings)
33
+ Bundler.settings["gems.graphql.pro"]
34
+ end
35
+ if creds.nil?
36
+ # Array form doesn't use a shell, and no secrets are in the arguments
37
+ output = IO.popen(["bundle", "config", "get", "gems.graphql.pro", "--parseable"], err: File::NULL, &:read)
38
+ creds = output[/[a-z0-9]{11}:[a-z0-9]{11}/]
39
+ end
40
+ creds = creds&.strip
41
+ creds && creds.match?(CREDENTIALS_PATTERN) ? creds : nil
42
+ rescue SystemCallError
43
+ nil
44
+ end
45
+
46
+ # Returns the SHA512 hex digest of the downloaded gem, or `nil` if the download failed.
47
+ def fetch_gem_digest(version, creds)
48
+ user, pass = creds.split(":", 2)
49
+ uri = URI.parse("https://gems.graphql.pro/gems/graphql-pro-#{version}.gem")
50
+ req = Net::HTTP::Get.new(uri)
51
+ req.basic_auth(user, pass)
52
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
53
+ res.is_a?(Net::HTTPSuccess) ? Digest::SHA512.hexdigest(res.body.to_s) : nil
54
+ end
55
+
56
+ # Returns the published digest at `uri`, or `nil` if it couldn't be fetched.
57
+ def fetch_published_digest(uri)
58
+ res = Net::HTTP.get_response(uri)
59
+ return nil unless res.is_a?(Net::HTTPSuccess)
60
+ # Remove final newline from .txt file
61
+ digest = res.body.to_s.strip
62
+ digest.match?(DIGEST_PATTERN) ? digest : nil
63
+ end
64
+ end
65
+
7
66
  desc "Get the checksum of a graphql-pro version and compare it to published versions on GitHub and graphql-ruby.org"
8
67
  task "graphql:pro:validate", [:gem_version] do |t, args|
9
- version = args[:gem_version]
10
- if version.nil?
68
+ if args[:gem_version].nil?
11
69
  raise ArgumentError, "A specific version is required, eg `rake graphql:pro:validate[1.12.0]`"
12
70
  end
71
+ version = Validate.normalize_version(args[:gem_version])
72
+ if version.nil?
73
+ raise ArgumentError, "Invalid version #{args[:gem_version].inspect}, expected a gem version like `rake graphql:pro:validate[1.12.0]`"
74
+ end
13
75
  check = "\e[32m✓\e[0m"
14
76
  ex = "\e[31m✘\e[0m"
15
77
  puts "Validating graphql-pro v#{version}"
16
78
  puts " - Checking for graphql-pro credentials..."
17
79
 
18
- creds = `bundle config gems.graphql.pro --parseable`[/[a-z0-9]{11}:[a-z0-9]{11}/]
80
+ creds = Validate.credentials
19
81
  if creds.nil?
20
82
  puts " #{ex} failed, please set with `bundle config gems.graphql.pro $MY_CREDENTIALS`"
21
83
  exit(1)
@@ -24,8 +86,8 @@ module GraphQL
24
86
  end
25
87
 
26
88
  puts " - Fetching the gem..."
27
- fetch_result = `gem fetch graphql-pro -v #{version} --source https://#{creds}@gems.graphql.pro`
28
- if fetch_result.empty?
89
+ gem_digest = Validate.fetch_gem_digest(version, creds)
90
+ if gem_digest.nil?
29
91
  puts " #{ex} failed to fetch v#{version}"
30
92
  exit(1)
31
93
  else
@@ -33,15 +95,8 @@ module GraphQL
33
95
  end
34
96
 
35
97
  puts " - Validating digest..."
36
- require "digest/sha2"
37
- gem_digest = Digest::SHA512.new.hexdigest(File.read("graphql-pro-#{version}.gem"))
38
- require "net/http"
39
- github_uri = URI("https://raw.githubusercontent.com/rmosolgo/graphql-ruby/master/guides/pro/checksums/graphql-pro-#{version}.txt")
40
- # Remove final newline from .txt file
41
- github_digest = Net::HTTP.get(github_uri).chomp
42
-
43
- docs_uri = URI("https://graphql-ruby.org/pro/checksums/graphql-pro-#{version}.txt")
44
- docs_digest = Net::HTTP.get(docs_uri).chomp
98
+ github_digest = Validate.fetch_published_digest(URI("https://raw.githubusercontent.com/rmosolgo/graphql-ruby/master/guides/pro/checksums/graphql-pro-#{version}.txt"))
99
+ docs_digest = Validate.fetch_published_digest(URI("https://graphql-ruby.org/pro/checksums/graphql-pro-#{version}.txt"))
45
100
 
46
101
  if docs_digest == gem_digest && github_digest == gem_digest
47
102
  puts " #{check} validated from GitHub"
@@ -49,11 +104,11 @@ module GraphQL
49
104
  else
50
105
  puts " #{ex} SHA mismatch:"
51
106
  puts " Downloaded: #{gem_digest}"
52
- puts " GitHub: #{github_digest}"
53
- puts " graphql-ruby.org: #{docs_digest}"
107
+ puts " GitHub: #{github_digest || "(not found)"}"
108
+ puts " graphql-ruby.org: #{docs_digest || "(not found)"}"
54
109
  puts ""
55
110
  puts " This download of graphql-pro is invalid, please open an issue:"
56
- puts " https://github.com/rmosolgo/graphql-ruby/issues/new?title=graphql-pro%20digest%20mismatch%20(#{version})"
111
+ puts " https://github.com/rmosolgo/graphql-ruby/issues/new?title=#{ERB::Util.url_encode("graphql-pro digest mismatch (#{version})")}"
57
112
  exit(1)
58
113
  end
59
114
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  require "fileutils"
3
4
  require "rake"
4
5
  require "graphql/rake_task/validate"
@@ -11,21 +12,32 @@ module GraphQL
11
12
  #
12
13
  # Use `load_context:` and `visible?` to dump schemas under certain visibility constraints.
13
14
  #
14
- # @example Dump a Schema to .graphql + .json files
15
- # require "graphql/rake_task"
16
- # GraphQL::RakeTask.new(schema_name: "MySchema")
15
+ # **Examples**
17
16
  #
18
- # # $ rake graphql:schema:dump
19
- # # Schema IDL dumped to ./schema.graphql
20
- # # Schema JSON dumped to ./schema.json
17
+ # **Example: Dump a Schema to .graphql + .json files**
21
18
  #
22
- # @example Invoking the task from Ruby
23
- # require "rake"
24
- # Rake::Task["graphql:schema:dump"].invoke
19
+ # ```ruby
20
+ # require "graphql/rake_task"
21
+ # GraphQL::RakeTask.new(schema_name: "MySchema")
25
22
  #
26
- # @example Providing arguments to build the introspection query
27
- # require "graphql/rake_task"
28
- # GraphQL::RakeTask.new(schema_name: "MySchema", include_is_one_of: true)
23
+ # # $ rake graphql:schema:dump
24
+ # # Schema IDL dumped to ./schema.graphql
25
+ # # Schema JSON dumped to ./schema.json
26
+ # ```
27
+ #
28
+ # **Example: Invoking the task from Ruby**
29
+ #
30
+ # ```ruby
31
+ # require "rake"
32
+ # Rake::Task["graphql:schema:dump"].invoke
33
+ # ```
34
+ #
35
+ # **Example: Providing arguments to build the introspection query**
36
+ #
37
+ # ```ruby
38
+ # require "graphql/rake_task"
39
+ # GraphQL::RakeTask.new(schema_name: "MySchema", include_is_one_of: true)
40
+ # ```
29
41
  class RakeTask
30
42
  include Rake::DSL
31
43
 
@@ -45,37 +57,57 @@ module GraphQL
45
57
  include_is_one_of: false
46
58
  }
47
59
 
48
- # @return [String] Namespace for generated tasks
60
+ # **Returns**
61
+ #
62
+ # - `String` — Namespace for generated tasks
49
63
  attr_writer :namespace
50
64
 
51
65
  def rake_namespace
52
66
  @namespace
53
67
  end
54
68
 
55
- # @return [Array<String>]
69
+ # **Returns**
70
+ #
71
+ # - `Array<String>`
56
72
  attr_accessor :dependencies
57
73
 
58
- # @return [String] By default, used to find the schema as a constant.
59
- # @see {#load_schema} for loading a schema another way
74
+ # See [load_schema](rdoc-ref:#load_schema) for loading a schema another way
75
+ #
76
+ # **Returns**
77
+ #
78
+ # - `String` — By default, used to find the schema as a constant.
60
79
  attr_accessor :schema_name
61
80
 
62
- # @return [<#call(task)>] A proc for loading the target GraphQL schema
81
+ # **Returns**
82
+ #
83
+ # - `<#call(task)>` — A proc for loading the target GraphQL schema
63
84
  attr_accessor :load_schema
64
85
 
65
- # @return [<#call(task)>] A callable for loading the query context
86
+ # **Returns**
87
+ #
88
+ # - `<#call(task)>` — A callable for loading the query context
66
89
  attr_accessor :load_context
67
90
 
68
- # @return [String] target for IDL task
91
+ # **Returns**
92
+ #
93
+ # - `String` — target for IDL task
69
94
  attr_accessor :idl_outfile
70
95
 
71
- # @return [String] target for JSON task
96
+ # **Returns**
97
+ #
98
+ # - `String` — target for JSON task
72
99
  attr_accessor :json_outfile
73
100
 
74
- # @return [String] directory for IDL & JSON files
101
+ # **Returns**
102
+ #
103
+ # - `String` — directory for IDL & JSON files
75
104
  attr_accessor :directory
76
105
 
77
- # @return [Boolean] Options for additional fields in the introspection query JSON response
78
- # @see GraphQL::Schema.as_json
106
+ # See [GraphQL::Schema.as_json](rdoc-ref:GraphQL::Schema.as_json).
107
+ #
108
+ # **Returns**
109
+ #
110
+ # - `Boolean` — Options for additional fields in the introspection query JSON response
79
111
  attr_accessor :include_deprecated_args, :include_schema_description, :include_is_repeatable, :include_specified_by_url, :include_is_one_of
80
112
 
81
113
  # Set the parameters of this task by passing keyword arguments