graphql 0.16.0 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (490) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +5 -0
  3. data/lib/generators/graphql/core.rb +69 -0
  4. data/lib/generators/graphql/enum_generator.rb +27 -0
  5. data/lib/generators/graphql/field_extractor.rb +31 -0
  6. data/lib/generators/graphql/input_generator.rb +50 -0
  7. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  8. data/lib/generators/graphql/install/templates/base_mutation.erb +10 -0
  9. data/lib/generators/graphql/install/templates/mutation_type.erb +12 -0
  10. data/lib/generators/graphql/install_generator.rb +197 -0
  11. data/lib/generators/graphql/interface_generator.rb +27 -0
  12. data/lib/generators/graphql/loader_generator.rb +21 -0
  13. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  15. data/lib/generators/graphql/mutation_generator.rb +30 -0
  16. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  17. data/lib/generators/graphql/object_generator.rb +50 -0
  18. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  19. data/lib/generators/graphql/relay.rb +49 -0
  20. data/lib/generators/graphql/relay_generator.rb +21 -0
  21. data/lib/generators/graphql/scalar_generator.rb +22 -0
  22. data/lib/generators/graphql/templates/base_argument.erb +6 -0
  23. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  24. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  25. data/lib/generators/graphql/templates/base_enum.erb +6 -0
  26. data/lib/generators/graphql/templates/base_field.erb +7 -0
  27. data/lib/generators/graphql/templates/base_input_object.erb +7 -0
  28. data/lib/generators/graphql/templates/base_interface.erb +9 -0
  29. data/lib/generators/graphql/templates/base_object.erb +7 -0
  30. data/lib/generators/graphql/templates/base_scalar.erb +6 -0
  31. data/lib/generators/graphql/templates/base_union.erb +6 -0
  32. data/lib/generators/graphql/templates/enum.erb +11 -0
  33. data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
  34. data/lib/generators/graphql/templates/input.erb +9 -0
  35. data/lib/generators/graphql/templates/interface.erb +10 -0
  36. data/lib/generators/graphql/templates/loader.erb +19 -0
  37. data/lib/generators/graphql/templates/mutation.erb +16 -0
  38. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  40. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  41. data/lib/generators/graphql/templates/node_type.erb +9 -0
  42. data/lib/generators/graphql/templates/object.erb +10 -0
  43. data/lib/generators/graphql/templates/query_type.erb +15 -0
  44. data/lib/generators/graphql/templates/scalar.erb +17 -0
  45. data/lib/generators/graphql/templates/schema.erb +30 -0
  46. data/lib/generators/graphql/templates/union.erb +9 -0
  47. data/lib/generators/graphql/type_generator.rb +135 -0
  48. data/lib/generators/graphql/union_generator.rb +33 -0
  49. data/lib/graphql/analysis/ast/analyzer.rb +84 -0
  50. data/lib/graphql/analysis/ast/field_usage.rb +57 -0
  51. data/lib/graphql/analysis/ast/max_query_complexity.rb +22 -0
  52. data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
  53. data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
  54. data/lib/graphql/analysis/ast/query_depth.rb +55 -0
  55. data/lib/graphql/analysis/ast/visitor.rb +269 -0
  56. data/lib/graphql/analysis/ast.rb +81 -0
  57. data/lib/graphql/analysis.rb +2 -5
  58. data/lib/graphql/analysis_error.rb +1 -0
  59. data/lib/graphql/backtrace/inspect_result.rb +50 -0
  60. data/lib/graphql/backtrace/table.rb +141 -0
  61. data/lib/graphql/backtrace/traced_error.rb +54 -0
  62. data/lib/graphql/backtrace/tracer.rb +80 -0
  63. data/lib/graphql/backtrace.rb +58 -0
  64. data/lib/graphql/coercion_error.rb +13 -0
  65. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  66. data/lib/graphql/dataloader/request.rb +19 -0
  67. data/lib/graphql/dataloader/request_all.rb +19 -0
  68. data/lib/graphql/dataloader/source.rb +164 -0
  69. data/lib/graphql/dataloader.rb +311 -0
  70. data/lib/graphql/date_encoding_error.rb +16 -0
  71. data/lib/graphql/deprecation.rb +9 -0
  72. data/lib/graphql/dig.rb +19 -0
  73. data/lib/graphql/execution/directive_checks.rb +37 -0
  74. data/lib/graphql/execution/errors.rb +93 -0
  75. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  76. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  77. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  78. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  79. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  80. data/lib/graphql/execution/interpreter/resolve.rb +77 -0
  81. data/lib/graphql/execution/interpreter/runtime.rb +994 -0
  82. data/lib/graphql/execution/interpreter.rb +226 -0
  83. data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
  84. data/lib/graphql/execution/lazy.rb +75 -0
  85. data/lib/graphql/execution/lookahead.rb +311 -0
  86. data/lib/graphql/execution/multiplex.rb +45 -0
  87. data/lib/graphql/execution.rb +18 -0
  88. data/lib/graphql/execution_error.rb +34 -1
  89. data/lib/graphql/filter.rb +53 -0
  90. data/lib/graphql/integer_decoding_error.rb +17 -0
  91. data/lib/graphql/integer_encoding_error.rb +36 -0
  92. data/lib/graphql/introspection/base_object.rb +13 -0
  93. data/lib/graphql/introspection/directive_location_enum.rb +12 -5
  94. data/lib/graphql/introspection/directive_type.rb +30 -10
  95. data/lib/graphql/introspection/dynamic_fields.rb +12 -0
  96. data/lib/graphql/introspection/entry_points.rb +22 -0
  97. data/lib/graphql/introspection/enum_value_type.rb +21 -8
  98. data/lib/graphql/introspection/field_type.rb +26 -10
  99. data/lib/graphql/introspection/input_value_type.rb +64 -14
  100. data/lib/graphql/introspection/introspection_query.rb +7 -76
  101. data/lib/graphql/introspection/schema_type.rb +42 -17
  102. data/lib/graphql/introspection/type_kind_enum.rb +11 -5
  103. data/lib/graphql/introspection/type_type.rb +104 -16
  104. data/lib/graphql/introspection.rb +104 -13
  105. data/lib/graphql/invalid_name_error.rb +11 -0
  106. data/lib/graphql/invalid_null_error.rb +36 -8
  107. data/lib/graphql/language/block_string.rb +99 -0
  108. data/lib/graphql/language/cache.rb +37 -0
  109. data/lib/graphql/language/definition_slice.rb +41 -0
  110. data/lib/graphql/language/document_from_schema_definition.rb +335 -0
  111. data/lib/graphql/language/generation.rb +16 -86
  112. data/lib/graphql/language/lexer.rb +1436 -705
  113. data/lib/graphql/language/lexer.rl +172 -64
  114. data/lib/graphql/language/nodes.rb +617 -105
  115. data/lib/graphql/language/parser.rb +1524 -430
  116. data/lib/graphql/language/parser.y +348 -73
  117. data/lib/graphql/language/printer.rb +386 -0
  118. data/lib/graphql/language/sanitized_printer.rb +222 -0
  119. data/lib/graphql/language/token.rb +16 -3
  120. data/lib/graphql/language/visitor.rb +169 -25
  121. data/lib/graphql/language.rb +30 -0
  122. data/lib/graphql/load_application_object_failed_error.rb +22 -0
  123. data/lib/graphql/name_validator.rb +11 -0
  124. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  125. data/lib/graphql/pagination/array_connection.rb +79 -0
  126. data/lib/graphql/pagination/connection.rb +253 -0
  127. data/lib/graphql/pagination/connections.rb +135 -0
  128. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  129. data/lib/graphql/pagination/relation_connection.rb +228 -0
  130. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  131. data/lib/graphql/pagination.rb +6 -0
  132. data/lib/graphql/parse_error.rb +24 -0
  133. data/lib/graphql/query/context.rb +266 -12
  134. data/lib/graphql/query/fingerprint.rb +26 -0
  135. data/lib/graphql/query/input_validation_result.rb +34 -7
  136. data/lib/graphql/query/null_context.rb +52 -0
  137. data/lib/graphql/query/result.rb +63 -0
  138. data/lib/graphql/query/validation_pipeline.rb +114 -0
  139. data/lib/graphql/query/variable_validation_error.rb +27 -3
  140. data/lib/graphql/query/variables.rb +75 -24
  141. data/lib/graphql/query.rb +359 -92
  142. data/lib/graphql/railtie.rb +13 -0
  143. data/lib/graphql/rake_task/validate.rb +63 -0
  144. data/lib/graphql/rake_task.rb +146 -0
  145. data/lib/graphql/relay/range_add.rb +52 -0
  146. data/lib/graphql/relay.rb +3 -0
  147. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  148. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  149. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  150. data/lib/graphql/rubocop.rb +4 -0
  151. data/lib/graphql/runtime_type_error.rb +5 -0
  152. data/lib/graphql/schema/addition.rb +245 -0
  153. data/lib/graphql/schema/argument.rb +395 -0
  154. data/lib/graphql/schema/base_64_bp.rb +26 -0
  155. data/lib/graphql/schema/base_64_encoder.rb +21 -0
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
  158. data/lib/graphql/schema/build_from_definition.rb +492 -0
  159. data/lib/graphql/schema/built_in_types.rb +12 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  161. data/lib/graphql/schema/directive/feature.rb +66 -0
  162. data/lib/graphql/schema/directive/flagged.rb +57 -0
  163. data/lib/graphql/schema/directive/include.rb +25 -0
  164. data/lib/graphql/schema/directive/one_of.rb +12 -0
  165. data/lib/graphql/schema/directive/skip.rb +25 -0
  166. data/lib/graphql/schema/directive/transform.rb +60 -0
  167. data/lib/graphql/schema/directive.rb +212 -0
  168. data/lib/graphql/schema/enum.rb +176 -0
  169. data/lib/graphql/schema/enum_value.rb +77 -0
  170. data/lib/graphql/schema/field/connection_extension.rb +80 -0
  171. data/lib/graphql/schema/field/scope_extension.rb +22 -0
  172. data/lib/graphql/schema/field.rb +862 -0
  173. data/lib/graphql/schema/field_extension.rb +156 -0
  174. data/lib/graphql/schema/find_inherited_value.rb +36 -0
  175. data/lib/graphql/schema/finder.rb +155 -0
  176. data/lib/graphql/schema/input_object.rb +258 -0
  177. data/lib/graphql/schema/interface.rb +113 -0
  178. data/lib/graphql/schema/introspection_system.rb +164 -0
  179. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  180. data/lib/graphql/schema/late_bound_type.rb +37 -0
  181. data/lib/graphql/schema/list.rb +86 -0
  182. data/lib/graphql/schema/loader.rb +228 -0
  183. data/lib/graphql/schema/member/base_dsl_methods.rb +124 -0
  184. data/lib/graphql/schema/member/build_type.rb +178 -0
  185. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  186. data/lib/graphql/schema/member/has_arguments.rb +376 -0
  187. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  188. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  189. data/lib/graphql/schema/member/has_directives.rb +113 -0
  190. data/lib/graphql/schema/member/has_fields.rb +163 -0
  191. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  192. data/lib/graphql/schema/member/has_path.rb +25 -0
  193. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  194. data/lib/graphql/schema/member/has_validators.rb +31 -0
  195. data/lib/graphql/schema/member/relay_shortcuts.rb +73 -0
  196. data/lib/graphql/schema/member/scoped.rb +21 -0
  197. data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
  198. data/lib/graphql/schema/member/validates_input.rb +33 -0
  199. data/lib/graphql/schema/member.rb +39 -0
  200. data/lib/graphql/schema/mutation.rb +85 -0
  201. data/lib/graphql/schema/non_null.rb +67 -0
  202. data/lib/graphql/schema/null_mask.rb +11 -0
  203. data/lib/graphql/schema/object.rb +117 -0
  204. data/lib/graphql/schema/printer.rb +72 -128
  205. data/lib/graphql/schema/relay_classic_mutation.rb +179 -0
  206. data/lib/graphql/schema/resolver/has_payload_type.rb +106 -0
  207. data/lib/graphql/schema/resolver.rb +402 -0
  208. data/lib/graphql/schema/scalar.rb +68 -0
  209. data/lib/graphql/schema/subscription.rb +148 -0
  210. data/lib/graphql/schema/timeout.rb +123 -0
  211. data/lib/graphql/schema/type_expression.rb +29 -5
  212. data/lib/graphql/schema/type_membership.rb +51 -0
  213. data/lib/graphql/schema/union.rb +81 -0
  214. data/lib/graphql/schema/unique_within_type.rb +34 -0
  215. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  216. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  217. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  218. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  219. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  220. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  221. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  222. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  223. data/lib/graphql/schema/validator.rb +171 -0
  224. data/lib/graphql/schema/warden.rb +413 -0
  225. data/lib/graphql/schema/wrapper.rb +24 -0
  226. data/lib/graphql/schema.rb +1179 -104
  227. data/lib/graphql/static_validation/all_rules.rb +14 -0
  228. data/lib/graphql/static_validation/base_visitor.rb +200 -0
  229. data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
  230. data/lib/graphql/static_validation/error.rb +46 -0
  231. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  232. data/lib/graphql/static_validation/literal_validator.rb +113 -22
  233. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +59 -11
  234. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
  235. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
  236. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  237. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +62 -8
  238. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
  239. data/lib/graphql/static_validation/rules/directives_are_defined.rb +20 -13
  240. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  241. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +32 -26
  242. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  243. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +21 -23
  244. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  245. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +55 -18
  246. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  247. data/lib/graphql/static_validation/rules/fields_will_merge.rb +390 -70
  248. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
  249. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
  250. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  251. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +54 -37
  252. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  253. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +26 -16
  254. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  255. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +13 -19
  256. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  257. data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
  258. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  259. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
  260. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  261. data/lib/graphql/static_validation/rules/fragments_are_used.rb +22 -33
  262. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  263. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  264. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  265. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
  266. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  267. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
  268. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  269. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  270. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  271. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
  272. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  273. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  274. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  275. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +22 -21
  276. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  277. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
  278. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  279. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
  280. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  281. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +56 -0
  282. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  283. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +36 -18
  284. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  285. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
  286. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  287. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +103 -39
  288. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  289. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +22 -14
  290. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  291. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +92 -70
  292. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  293. data/lib/graphql/static_validation/type_stack.rb +85 -24
  294. data/lib/graphql/static_validation/validation_context.rb +25 -46
  295. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  296. data/lib/graphql/static_validation/validator.rb +46 -15
  297. data/lib/graphql/static_validation.rb +6 -3
  298. data/lib/graphql/string_encoding_error.rb +20 -0
  299. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +247 -0
  300. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  301. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  302. data/lib/graphql/subscriptions/event.rb +144 -0
  303. data/lib/graphql/subscriptions/instrumentation.rb +28 -0
  304. data/lib/graphql/subscriptions/serialize.rb +158 -0
  305. data/lib/graphql/subscriptions.rb +306 -0
  306. data/lib/graphql/tracing/active_support_notifications_tracing.rb +21 -0
  307. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  308. data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
  309. data/lib/graphql/tracing/data_dog_tracing.rb +100 -0
  310. data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
  311. data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
  312. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  313. data/lib/graphql/tracing/platform_tracing.rb +122 -0
  314. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
  315. data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
  316. data/lib/graphql/tracing/scout_tracing.rb +54 -0
  317. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  318. data/lib/graphql/tracing.rb +94 -0
  319. data/lib/graphql/type_kinds.rb +50 -22
  320. data/lib/graphql/types/big_int.rb +23 -0
  321. data/lib/graphql/types/boolean.rb +18 -0
  322. data/lib/graphql/types/float.rb +19 -0
  323. data/lib/graphql/types/id.rb +24 -0
  324. data/lib/graphql/types/int.rb +36 -0
  325. data/lib/graphql/types/iso_8601_date.rb +45 -0
  326. data/lib/graphql/types/iso_8601_date_time.rb +76 -0
  327. data/lib/graphql/types/json.rb +25 -0
  328. data/lib/graphql/types/relay/base_connection.rb +49 -0
  329. data/lib/graphql/types/relay/base_edge.rb +29 -0
  330. data/lib/graphql/types/relay/connection_behaviors.rb +154 -0
  331. data/lib/graphql/types/relay/default_relay.rb +21 -0
  332. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  333. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  334. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  335. data/lib/graphql/types/relay/node.rb +15 -0
  336. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  337. data/lib/graphql/types/relay/page_info.rb +11 -0
  338. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  339. data/lib/graphql/types/relay.rb +39 -0
  340. data/lib/graphql/types/string.rb +29 -0
  341. data/lib/graphql/types.rb +11 -0
  342. data/lib/graphql/unauthorized_error.rb +29 -0
  343. data/lib/graphql/unauthorized_field_error.rb +23 -0
  344. data/lib/graphql/unresolved_type_error.rb +35 -0
  345. data/lib/graphql/version.rb +2 -1
  346. data/lib/graphql.rb +86 -41
  347. data/readme.md +15 -101
  348. metadata +394 -279
  349. data/lib/graphql/analysis/analyze_query.rb +0 -73
  350. data/lib/graphql/analysis/max_query_complexity.rb +0 -25
  351. data/lib/graphql/analysis/max_query_depth.rb +0 -25
  352. data/lib/graphql/analysis/query_complexity.rb +0 -122
  353. data/lib/graphql/analysis/query_depth.rb +0 -54
  354. data/lib/graphql/argument.rb +0 -25
  355. data/lib/graphql/base_type.rb +0 -115
  356. data/lib/graphql/boolean_type.rb +0 -9
  357. data/lib/graphql/define/assign_argument.rb +0 -20
  358. data/lib/graphql/define/assign_enum_value.rb +0 -16
  359. data/lib/graphql/define/assign_object_field.rb +0 -21
  360. data/lib/graphql/define/assignment_dictionary.rb +0 -26
  361. data/lib/graphql/define/defined_object_proxy.rb +0 -32
  362. data/lib/graphql/define/instance_definable.rb +0 -79
  363. data/lib/graphql/define/non_null_with_bang.rb +0 -15
  364. data/lib/graphql/define/type_definer.rb +0 -30
  365. data/lib/graphql/define.rb +0 -8
  366. data/lib/graphql/directive/include_directive.rb +0 -10
  367. data/lib/graphql/directive/skip_directive.rb +0 -11
  368. data/lib/graphql/directive.rb +0 -49
  369. data/lib/graphql/enum_type.rb +0 -95
  370. data/lib/graphql/field.rb +0 -131
  371. data/lib/graphql/float_type.rb +0 -5
  372. data/lib/graphql/id_type.rb +0 -12
  373. data/lib/graphql/input_object_type.rb +0 -71
  374. data/lib/graphql/int_type.rb +0 -5
  375. data/lib/graphql/interface_type.rb +0 -38
  376. data/lib/graphql/internal_representation/node.rb +0 -81
  377. data/lib/graphql/internal_representation/rewrite.rb +0 -177
  378. data/lib/graphql/internal_representation.rb +0 -2
  379. data/lib/graphql/introspection/arguments_field.rb +0 -5
  380. data/lib/graphql/introspection/enum_values_field.rb +0 -13
  381. data/lib/graphql/introspection/fields_field.rb +0 -13
  382. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  383. data/lib/graphql/introspection/interfaces_field.rb +0 -5
  384. data/lib/graphql/introspection/of_type_field.rb +0 -6
  385. data/lib/graphql/introspection/possible_types_field.rb +0 -11
  386. data/lib/graphql/introspection/schema_field.rb +0 -15
  387. data/lib/graphql/introspection/type_by_name_field.rb +0 -16
  388. data/lib/graphql/introspection/typename_field.rb +0 -15
  389. data/lib/graphql/list_type.rb +0 -46
  390. data/lib/graphql/non_null_type.rb +0 -43
  391. data/lib/graphql/object_type.rb +0 -93
  392. data/lib/graphql/query/arguments.rb +0 -76
  393. data/lib/graphql/query/directive_resolution.rb +0 -16
  394. data/lib/graphql/query/executor.rb +0 -45
  395. data/lib/graphql/query/literal_input.rb +0 -90
  396. data/lib/graphql/query/serial_execution/execution_context.rb +0 -31
  397. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -82
  398. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -27
  399. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -42
  400. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -107
  401. data/lib/graphql/query/serial_execution.rb +0 -41
  402. data/lib/graphql/query/type_resolver.rb +0 -25
  403. data/lib/graphql/scalar_type.rb +0 -53
  404. data/lib/graphql/schema/catchall_middleware.rb +0 -34
  405. data/lib/graphql/schema/middleware_chain.rb +0 -28
  406. data/lib/graphql/schema/possible_types.rb +0 -34
  407. data/lib/graphql/schema/reduce_types.rb +0 -68
  408. data/lib/graphql/schema/rescue_middleware.rb +0 -53
  409. data/lib/graphql/schema/timeout_middleware.rb +0 -67
  410. data/lib/graphql/schema/type_map.rb +0 -30
  411. data/lib/graphql/schema/validation.rb +0 -164
  412. data/lib/graphql/static_validation/arguments_validator.rb +0 -48
  413. data/lib/graphql/static_validation/message.rb +0 -36
  414. data/lib/graphql/string_type.rb +0 -5
  415. data/lib/graphql/union_type.rb +0 -38
  416. data/spec/graphql/analysis/analyze_query_spec.rb +0 -50
  417. data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -62
  418. data/spec/graphql/analysis/max_query_depth_spec.rb +0 -100
  419. data/spec/graphql/analysis/query_complexity_spec.rb +0 -235
  420. data/spec/graphql/analysis/query_depth_spec.rb +0 -80
  421. data/spec/graphql/argument_spec.rb +0 -20
  422. data/spec/graphql/base_type_spec.rb +0 -24
  423. data/spec/graphql/boolean_type_spec.rb +0 -20
  424. data/spec/graphql/define/instance_definable_spec.rb +0 -55
  425. data/spec/graphql/directive_spec.rb +0 -77
  426. data/spec/graphql/enum_type_spec.rb +0 -31
  427. data/spec/graphql/execution_error_spec.rb +0 -61
  428. data/spec/graphql/field_spec.rb +0 -92
  429. data/spec/graphql/float_type_spec.rb +0 -15
  430. data/spec/graphql/id_type_spec.rb +0 -32
  431. data/spec/graphql/input_object_type_spec.rb +0 -162
  432. data/spec/graphql/int_type_spec.rb +0 -15
  433. data/spec/graphql/interface_type_spec.rb +0 -56
  434. data/spec/graphql/internal_representation/rewrite_spec.rb +0 -120
  435. data/spec/graphql/introspection/directive_type_spec.rb +0 -50
  436. data/spec/graphql/introspection/input_value_type_spec.rb +0 -42
  437. data/spec/graphql/introspection/introspection_query_spec.rb +0 -10
  438. data/spec/graphql/introspection/schema_type_spec.rb +0 -45
  439. data/spec/graphql/introspection/type_type_spec.rb +0 -122
  440. data/spec/graphql/language/generation_spec.rb +0 -42
  441. data/spec/graphql/language/parser_spec.rb +0 -442
  442. data/spec/graphql/language/visitor_spec.rb +0 -49
  443. data/spec/graphql/list_type_spec.rb +0 -32
  444. data/spec/graphql/non_null_type_spec.rb +0 -31
  445. data/spec/graphql/object_type_spec.rb +0 -42
  446. data/spec/graphql/query/arguments_spec.rb +0 -25
  447. data/spec/graphql/query/context_spec.rb +0 -83
  448. data/spec/graphql/query/executor_spec.rb +0 -273
  449. data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -53
  450. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -66
  451. data/spec/graphql/query/type_resolver_spec.rb +0 -8
  452. data/spec/graphql/query/variables_spec.rb +0 -28
  453. data/spec/graphql/query_spec.rb +0 -363
  454. data/spec/graphql/scalar_type_spec.rb +0 -61
  455. data/spec/graphql/schema/catchall_middleware_spec.rb +0 -32
  456. data/spec/graphql/schema/middleware_chain_spec.rb +0 -42
  457. data/spec/graphql/schema/printer_spec.rb +0 -190
  458. data/spec/graphql/schema/reduce_types_spec.rb +0 -102
  459. data/spec/graphql/schema/rescue_middleware_spec.rb +0 -33
  460. data/spec/graphql/schema/timeout_middleware_spec.rb +0 -180
  461. data/spec/graphql/schema/type_expression_spec.rb +0 -38
  462. data/spec/graphql/schema/validation_spec.rb +0 -219
  463. data/spec/graphql/schema_spec.rb +0 -23
  464. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -63
  465. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -48
  466. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -34
  467. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -39
  468. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -60
  469. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -31
  470. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -48
  471. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -47
  472. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -39
  473. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -44
  474. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -49
  475. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -25
  476. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -42
  477. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -44
  478. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -63
  479. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -37
  480. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -53
  481. data/spec/graphql/static_validation/type_stack_spec.rb +0 -37
  482. data/spec/graphql/static_validation/validator_spec.rb +0 -69
  483. data/spec/graphql/string_type_spec.rb +0 -15
  484. data/spec/graphql/union_type_spec.rb +0 -31
  485. data/spec/spec_helper.rb +0 -18
  486. data/spec/support/dairy_app.rb +0 -309
  487. data/spec/support/dairy_data.rb +0 -23
  488. data/spec/support/minimum_input_object.rb +0 -16
  489. data/spec/support/star_wars_data.rb +0 -71
  490. data/spec/support/star_wars_schema.rb +0 -76
@@ -0,0 +1,269 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ module AST
5
+ # Depth first traversal through a query AST, calling AST analyzers
6
+ # along the way.
7
+ #
8
+ # The visitor is a special case of GraphQL::Language::Visitor, visiting
9
+ # only the selected operation, providing helpers for common use cases such
10
+ # as skipped fields and visiting fragment spreads.
11
+ #
12
+ # @see {GraphQL::Analysis::AST::Analyzer} AST Analyzers for queries
13
+ class Visitor < GraphQL::Language::Visitor
14
+ def initialize(query:, analyzers:)
15
+ @analyzers = analyzers
16
+ @path = []
17
+ @object_types = []
18
+ @directives = []
19
+ @field_definitions = []
20
+ @argument_definitions = []
21
+ @directive_definitions = []
22
+ @rescued_errors = []
23
+ @query = query
24
+ @schema = query.schema
25
+ @response_path = []
26
+ @skip_stack = [false]
27
+ super(query.selected_operation)
28
+ end
29
+
30
+ # @return [GraphQL::Query] the query being visited
31
+ attr_reader :query
32
+
33
+ # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
34
+ attr_reader :object_types
35
+
36
+ # @return [Array<GraphQL::AnalysisError]
37
+ attr_reader :rescued_errors
38
+
39
+ def visit
40
+ return unless @document
41
+ super
42
+ end
43
+
44
+ # Visit Helpers
45
+
46
+ # @return [GraphQL::Execution::Interpreter::Arguments] Arguments for this node, merging default values, literal values and query variables
47
+ # @see {GraphQL::Query#arguments_for}
48
+ def arguments_for(ast_node, field_definition)
49
+ @query.arguments_for(ast_node, field_definition)
50
+ end
51
+
52
+ # @return [Boolean] If the visitor is currently inside a fragment definition
53
+ def visiting_fragment_definition?
54
+ @in_fragment_def
55
+ end
56
+
57
+ # @return [Boolean] If the current node should be skipped because of a skip or include directive
58
+ def skipping?
59
+ @skipping
60
+ end
61
+
62
+ # @return [Array<String>] The path to the response key for the current field
63
+ def response_path
64
+ @response_path.dup
65
+ end
66
+
67
+ # Visitor Hooks
68
+
69
+ def on_operation_definition(node, parent)
70
+ object_type = @schema.root_type_for_operation(node.operation_type)
71
+ @object_types.push(object_type)
72
+ @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
73
+ call_analyzers(:on_enter_operation_definition, node, parent)
74
+ super
75
+ call_analyzers(:on_leave_operation_definition, node, parent)
76
+ @object_types.pop
77
+ @path.pop
78
+ end
79
+
80
+ def on_fragment_definition(node, parent)
81
+ on_fragment_with_type(node) do
82
+ @path.push("fragment #{node.name}")
83
+ @in_fragment_def = false
84
+ call_analyzers(:on_enter_fragment_definition, node, parent)
85
+ super
86
+ @in_fragment_def = false
87
+ call_analyzers(:on_leave_fragment_definition, node, parent)
88
+ end
89
+ end
90
+
91
+ def on_inline_fragment(node, parent)
92
+ on_fragment_with_type(node) do
93
+ @path.push("...#{node.type ? " on #{node.type.name}" : ""}")
94
+ call_analyzers(:on_enter_inline_fragment, node, parent)
95
+ super
96
+ call_analyzers(:on_leave_inline_fragment, node, parent)
97
+ end
98
+ end
99
+
100
+ def on_field(node, parent)
101
+ @response_path.push(node.alias || node.name)
102
+ parent_type = @object_types.last
103
+ # This could be nil if the previous field wasn't found:
104
+ field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context)
105
+ @field_definitions.push(field_definition)
106
+ if !field_definition.nil?
107
+ next_object_type = field_definition.type.unwrap
108
+ @object_types.push(next_object_type)
109
+ else
110
+ @object_types.push(nil)
111
+ end
112
+ @path.push(node.alias || node.name)
113
+
114
+ @skipping = @skip_stack.last || skip?(node)
115
+ @skip_stack << @skipping
116
+
117
+ call_analyzers(:on_enter_field, node, parent)
118
+ super
119
+
120
+ @skipping = @skip_stack.pop
121
+
122
+ call_analyzers(:on_leave_field, node, parent)
123
+ @response_path.pop
124
+ @field_definitions.pop
125
+ @object_types.pop
126
+ @path.pop
127
+ end
128
+
129
+ def on_directive(node, parent)
130
+ directive_defn = @schema.directives[node.name]
131
+ @directive_definitions.push(directive_defn)
132
+ call_analyzers(:on_enter_directive, node, parent)
133
+ super
134
+ call_analyzers(:on_leave_directive, node, parent)
135
+ @directive_definitions.pop
136
+ end
137
+
138
+ def on_argument(node, parent)
139
+ argument_defn = if (arg = @argument_definitions.last)
140
+ arg_type = arg.type.unwrap
141
+ if arg_type.kind.input_object?
142
+ arg_type.get_argument(node.name, @query.context)
143
+ else
144
+ nil
145
+ end
146
+ elsif (directive_defn = @directive_definitions.last)
147
+ directive_defn.get_argument(node.name, @query.context)
148
+ elsif (field_defn = @field_definitions.last)
149
+ field_defn.get_argument(node.name, @query.context)
150
+ else
151
+ nil
152
+ end
153
+
154
+ @argument_definitions.push(argument_defn)
155
+ @path.push(node.name)
156
+ call_analyzers(:on_enter_argument, node, parent)
157
+ super
158
+ call_analyzers(:on_leave_argument, node, parent)
159
+ @argument_definitions.pop
160
+ @path.pop
161
+ end
162
+
163
+ def on_fragment_spread(node, parent)
164
+ @path.push("... #{node.name}")
165
+ call_analyzers(:on_enter_fragment_spread, node, parent)
166
+ enter_fragment_spread_inline(node)
167
+ super
168
+ leave_fragment_spread_inline(node)
169
+ call_analyzers(:on_leave_fragment_spread, node, parent)
170
+ @path.pop
171
+ end
172
+
173
+ def on_abstract_node(node, parent)
174
+ call_analyzers(:on_enter_abstract_node, node, parent)
175
+ super
176
+ call_analyzers(:on_leave_abstract_node, node, parent)
177
+ end
178
+
179
+ # @return [GraphQL::BaseType] The current object type
180
+ def type_definition
181
+ @object_types.last
182
+ end
183
+
184
+ # @return [GraphQL::BaseType] The type which the current type came from
185
+ def parent_type_definition
186
+ @object_types[-2]
187
+ end
188
+
189
+ # @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
190
+ def field_definition
191
+ @field_definitions.last
192
+ end
193
+
194
+ # @return [GraphQL::Field, nil] The GraphQL field which returned the object that the current field belongs to
195
+ def previous_field_definition
196
+ @field_definitions[-2]
197
+ end
198
+
199
+ # @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
200
+ def directive_definition
201
+ @directive_definitions.last
202
+ end
203
+
204
+ # @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
205
+ def argument_definition
206
+ @argument_definitions.last
207
+ end
208
+
209
+ # @return [GraphQL::Argument, nil] The previous GraphQL argument
210
+ def previous_argument_definition
211
+ @argument_definitions[-2]
212
+ end
213
+
214
+ private
215
+
216
+ # Visit a fragment spread inline instead of visiting the definition
217
+ # by itself.
218
+ def enter_fragment_spread_inline(fragment_spread)
219
+ fragment_def = query.fragments[fragment_spread.name]
220
+
221
+ object_type = if fragment_def.type
222
+ @query.warden.get_type(fragment_def.type.name)
223
+ else
224
+ object_types.last
225
+ end
226
+
227
+ object_types << object_type
228
+
229
+ fragment_def.selections.each do |selection|
230
+ visit_node(selection, fragment_def)
231
+ end
232
+ end
233
+
234
+ # Visit a fragment spread inline instead of visiting the definition
235
+ # by itself.
236
+ def leave_fragment_spread_inline(_fragment_spread)
237
+ object_types.pop
238
+ end
239
+
240
+ def skip?(ast_node)
241
+ dir = ast_node.directives
242
+ dir.any? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
243
+ end
244
+
245
+ def call_analyzers(method, node, parent)
246
+ @analyzers.each do |analyzer|
247
+ begin
248
+ analyzer.public_send(method, node, parent, self)
249
+ rescue AnalysisError => err
250
+ @rescued_errors << err
251
+ end
252
+ end
253
+ end
254
+
255
+ def on_fragment_with_type(node)
256
+ object_type = if node.type
257
+ @query.warden.get_type(node.type.name)
258
+ else
259
+ @object_types.last
260
+ end
261
+ @object_types.push(object_type)
262
+ yield(node)
263
+ @object_types.pop
264
+ @path.pop
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/analysis/ast/visitor"
3
+ require "graphql/analysis/ast/analyzer"
4
+ require "graphql/analysis/ast/field_usage"
5
+ require "graphql/analysis/ast/query_complexity"
6
+ require "graphql/analysis/ast/max_query_complexity"
7
+ require "graphql/analysis/ast/query_depth"
8
+ require "graphql/analysis/ast/max_query_depth"
9
+
10
+ module GraphQL
11
+ module Analysis
12
+ module AST
13
+ module_function
14
+ # Analyze a multiplex, and all queries within.
15
+ # Multiplex analyzers are ran for all queries, keeping state.
16
+ # Query analyzers are ran per query, without carrying state between queries.
17
+ #
18
+ # @param multiplex [GraphQL::Execution::Multiplex]
19
+ # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
20
+ # @return [Array<Any>] Results from multiplex analyzers
21
+ def analyze_multiplex(multiplex, analyzers)
22
+ multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
23
+
24
+ multiplex.trace("analyze_multiplex", { multiplex: multiplex }) do
25
+ query_results = multiplex.queries.map do |query|
26
+ if query.valid?
27
+ analyze_query(
28
+ query,
29
+ query.analyzers,
30
+ multiplex_analyzers: multiplex_analyzers
31
+ )
32
+ else
33
+ []
34
+ end
35
+ end
36
+
37
+ multiplex_results = multiplex_analyzers.map(&:result)
38
+ multiplex_errors = analysis_errors(multiplex_results)
39
+
40
+ multiplex.queries.each_with_index do |query, idx|
41
+ query.analysis_errors = multiplex_errors + analysis_errors(query_results[idx])
42
+ end
43
+ multiplex_results
44
+ end
45
+ end
46
+
47
+ # @param query [GraphQL::Query]
48
+ # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
49
+ # @return [Array<Any>] Results from those analyzers
50
+ def analyze_query(query, analyzers, multiplex_analyzers: [])
51
+ query.trace("analyze_query", { query: query }) do
52
+ query_analyzers = analyzers
53
+ .map { |analyzer| analyzer.new(query) }
54
+ .select { |analyzer| analyzer.analyze? }
55
+
56
+ analyzers_to_run = query_analyzers + multiplex_analyzers
57
+ if analyzers_to_run.any?
58
+ visitor = GraphQL::Analysis::AST::Visitor.new(
59
+ query: query,
60
+ analyzers: analyzers_to_run
61
+ )
62
+
63
+ visitor.visit
64
+
65
+ if visitor.rescued_errors.any?
66
+ visitor.rescued_errors
67
+ else
68
+ query_analyzers.map(&:result)
69
+ end
70
+ else
71
+ []
72
+ end
73
+ end
74
+ end
75
+
76
+ def analysis_errors(results)
77
+ results.flatten.select { |r| r.is_a?(GraphQL::AnalysisError) }
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,5 +1,2 @@
1
- require "graphql/analysis/max_query_complexity"
2
- require "graphql/analysis/max_query_depth"
3
- require "graphql/analysis/query_complexity"
4
- require "graphql/analysis/query_depth"
5
- require "graphql/analysis/analyze_query"
1
+ # frozen_string_literal: true
2
+ require "graphql/analysis/ast"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class AnalysisError < GraphQL::ExecutionError
3
4
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ module InspectResult
5
+ module_function
6
+
7
+ def inspect_result(obj)
8
+ case obj
9
+ when Hash
10
+ "{" +
11
+ obj.map do |key, val|
12
+ "#{key}: #{inspect_truncated(val)}"
13
+ end.join(", ") +
14
+ "}"
15
+ when Array
16
+ "[" +
17
+ obj.map { |v| inspect_truncated(v) }.join(", ") +
18
+ "]"
19
+ when Query::Context::SharedMethods
20
+ if obj.invalid_null?
21
+ "nil"
22
+ else
23
+ inspect_truncated(obj.value)
24
+ end
25
+ else
26
+ inspect_truncated(obj)
27
+ end
28
+ end
29
+
30
+ def inspect_truncated(obj)
31
+ case obj
32
+ when Hash
33
+ "{...}"
34
+ when Array
35
+ "[...]"
36
+ when Query::Context::SharedMethods
37
+ if obj.invalid_null?
38
+ "nil"
39
+ else
40
+ inspect_truncated(obj.value)
41
+ end
42
+ when GraphQL::Execution::Lazy
43
+ "(unresolved)"
44
+ else
45
+ "#{obj.inspect}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ # A class for turning a context into a human-readable table or array
5
+ class Table
6
+ MIN_COL_WIDTH = 4
7
+ MAX_COL_WIDTH = 100
8
+ HEADERS = [
9
+ "Loc",
10
+ "Field",
11
+ "Object",
12
+ "Arguments",
13
+ "Result",
14
+ ]
15
+
16
+ def initialize(context, value:)
17
+ @context = context
18
+ @override_value = value
19
+ end
20
+
21
+ # @return [String] A table layout of backtrace with metadata
22
+ def to_table
23
+ @to_table ||= render_table(rows)
24
+ end
25
+
26
+ # @return [Array<String>] An array of position + field name entries
27
+ def to_backtrace
28
+ @to_backtrace ||= begin
29
+ backtrace = rows.map { |r| "#{r[0]}: #{r[1]}" }
30
+ # skip the header entry
31
+ backtrace.shift
32
+ backtrace
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def rows
39
+ @rows ||= build_rows(@context, rows: [HEADERS], top: true)
40
+ end
41
+
42
+ # @return [String]
43
+ def render_table(rows)
44
+ max = Array.new(HEADERS.length, MIN_COL_WIDTH)
45
+
46
+ rows.each do |row|
47
+ row.each_with_index do |col, idx|
48
+ col_len = col.length
49
+ max_len = max[idx]
50
+ if col_len > max_len
51
+ if col_len > MAX_COL_WIDTH
52
+ max[idx] = MAX_COL_WIDTH
53
+ else
54
+ max[idx] = col_len
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ table = "".dup
61
+ last_col_idx = max.length - 1
62
+ rows.each do |row|
63
+ table << row.map.each_with_index do |col, idx|
64
+ max_len = max[idx]
65
+ if idx < last_col_idx
66
+ col = col.ljust(max_len)
67
+ end
68
+ if col.length > max_len
69
+ col = col[0, max_len - 3] + "..."
70
+ end
71
+ col
72
+ end.join(" | ")
73
+ table << "\n"
74
+ end
75
+ table
76
+ end
77
+
78
+ # @return [Array] 5 items for a backtrace table (not `key`)
79
+ def build_rows(context_entry, rows:, top: false)
80
+ case context_entry
81
+ when Backtrace::Frame
82
+ field_alias = context_entry.ast_node.respond_to?(:alias) && context_entry.ast_node.alias
83
+ value = if top && @override_value
84
+ @override_value
85
+ else
86
+ value_at(@context.query.context.namespace(:interpreter_runtime)[:runtime], context_entry.path)
87
+ end
88
+ rows << [
89
+ "#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
90
+ "#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
91
+ "#{context_entry.object.object.inspect}",
92
+ context_entry.arguments.to_h.inspect, # rubocop:disable Development/ContextIsPassedCop -- unrelated method
93
+ Backtrace::InspectResult.inspect_result(value),
94
+ ]
95
+ if (parent = context_entry.parent_frame)
96
+ build_rows(parent, rows: rows)
97
+ else
98
+ rows
99
+ end
100
+ when GraphQL::Query::Context
101
+ query = context_entry.query
102
+ op = query.selected_operation
103
+ if op
104
+ op_type = op.operation_type
105
+ position = "#{op.line}:#{op.col}"
106
+ else
107
+ op_type = "query"
108
+ position = "?:?"
109
+ end
110
+ op_name = query.selected_operation_name
111
+ object = query.root_value
112
+ if object.is_a?(GraphQL::Schema::Object)
113
+ object = object.object
114
+ end
115
+ value = value_at(context_entry.namespace(:interpreter_runtime)[:runtime], [])
116
+ rows << [
117
+ "#{position}",
118
+ "#{op_type}#{op_name ? " #{op_name}" : ""}",
119
+ "#{object.inspect}",
120
+ query.variables.to_h.inspect,
121
+ Backtrace::InspectResult.inspect_result(value),
122
+ ]
123
+ else
124
+ raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
125
+ end
126
+ end
127
+
128
+ def value_at(runtime, path)
129
+ response = runtime.final_result
130
+ path.each do |key|
131
+ if response && (response = response[key])
132
+ next
133
+ else
134
+ break
135
+ end
136
+ end
137
+ response
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ # When {Backtrace} is enabled, raised errors are wrapped with {TracedError}.
5
+ class TracedError < GraphQL::Error
6
+ # @return [Array<String>] Printable backtrace of GraphQL error context
7
+ attr_reader :graphql_backtrace
8
+
9
+ # @return [GraphQL::Query::Context] The context at the field where the error was raised
10
+ attr_reader :context
11
+
12
+ MESSAGE_TEMPLATE = <<-MESSAGE
13
+ Unhandled error during GraphQL execution:
14
+
15
+ %{cause_message}
16
+ %{cause_backtrace}
17
+ %{cause_backtrace_more}
18
+ Use #cause to access the original exception (including #cause.backtrace).
19
+
20
+ GraphQL Backtrace:
21
+ %{graphql_table}
22
+ MESSAGE
23
+
24
+ # This many lines of the original Ruby backtrace
25
+ # are included in the message
26
+ CAUSE_BACKTRACE_PREVIEW_LENGTH = 10
27
+
28
+ def initialize(err, current_ctx)
29
+ @context = current_ctx
30
+ backtrace = Backtrace.new(current_ctx, value: err)
31
+ @graphql_backtrace = backtrace.to_a
32
+
33
+ cause_backtrace_preview = err.backtrace.first(CAUSE_BACKTRACE_PREVIEW_LENGTH).join("\n ")
34
+
35
+ cause_backtrace_remainder_length = err.backtrace.length - CAUSE_BACKTRACE_PREVIEW_LENGTH
36
+ cause_backtrace_more = if cause_backtrace_remainder_length < 0
37
+ ""
38
+ elsif cause_backtrace_remainder_length == 1
39
+ "... and 1 more line\n"
40
+ else
41
+ "... and #{cause_backtrace_remainder_length} more lines\n"
42
+ end
43
+
44
+ message = MESSAGE_TEMPLATE % {
45
+ cause_message: err.message,
46
+ cause_backtrace: cause_backtrace_preview,
47
+ cause_backtrace_more: cause_backtrace_more,
48
+ graphql_table: backtrace.inspect,
49
+ }
50
+ super(message)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ # TODO this is not fiber-friendly
5
+ module Tracer
6
+ module_function
7
+
8
+ # Implement the {GraphQL::Tracing} API.
9
+ def trace(key, metadata)
10
+ case key
11
+ when "lex", "parse"
12
+ # No context here, don't have a query yet
13
+ nil
14
+ when "execute_multiplex", "analyze_multiplex"
15
+ # No query context yet
16
+ nil
17
+ when "validate", "analyze_query", "execute_query", "execute_query_lazy"
18
+ push_key = []
19
+ if (query = metadata[:query]) || ((queries = metadata[:queries]) && (query = queries.first))
20
+ push_data = query
21
+ multiplex = query.multiplex
22
+ elsif (multiplex = metadata[:multiplex])
23
+ push_data = multiplex.queries.first
24
+ end
25
+ when "execute_field", "execute_field_lazy"
26
+ query = metadata[:query]
27
+ multiplex = query.multiplex
28
+ push_key = metadata[:path]
29
+ parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]
30
+
31
+ if parent_frame.is_a?(GraphQL::Query)
32
+ parent_frame = parent_frame.context
33
+ end
34
+
35
+ push_data = Frame.new(
36
+ query: query,
37
+ path: push_key,
38
+ ast_node: metadata[:ast_node],
39
+ field: metadata[:field],
40
+ object: metadata[:object],
41
+ arguments: metadata[:arguments],
42
+ parent_frame: parent_frame,
43
+ )
44
+ else
45
+ # Custom key, no backtrace data for this
46
+ nil
47
+ end
48
+
49
+ if push_data && multiplex
50
+ push_storage = multiplex.context[:graphql_backtrace_contexts] ||= {}
51
+ push_storage[push_key] = push_data
52
+ multiplex.context[:last_graphql_backtrace_context] = push_data
53
+ end
54
+
55
+ if key == "execute_multiplex"
56
+ multiplex_context = metadata[:multiplex].context
57
+ begin
58
+ yield
59
+ rescue StandardError => err
60
+ # This is an unhandled error from execution,
61
+ # Re-raise it with a GraphQL trace.
62
+ potential_context = multiplex_context[:last_graphql_backtrace_context]
63
+
64
+ if potential_context.is_a?(GraphQL::Query::Context) ||
65
+ potential_context.is_a?(Backtrace::Frame)
66
+ raise TracedError.new(err, potential_context)
67
+ else
68
+ raise
69
+ end
70
+ ensure
71
+ multiplex_context.delete(:graphql_backtrace_contexts)
72
+ multiplex_context.delete(:last_graphql_backtrace_context)
73
+ end
74
+ else
75
+ yield
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end