graphql 1.12.12 → 2.2.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (392) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +14 -4
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_generator.rb +5 -30
  14. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  15. data/lib/generators/graphql/object_generator.rb +10 -38
  16. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  17. data/lib/generators/graphql/relay.rb +23 -12
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  20. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  21. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  22. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  23. data/lib/generators/graphql/templates/base_field.erb +2 -0
  24. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  25. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  26. data/lib/generators/graphql/templates/base_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  28. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  29. data/lib/generators/graphql/templates/base_union.erb +2 -0
  30. data/lib/generators/graphql/templates/enum.erb +5 -1
  31. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  32. data/lib/generators/graphql/templates/input.erb +9 -0
  33. data/lib/generators/graphql/templates/interface.erb +4 -2
  34. data/lib/generators/graphql/templates/loader.erb +2 -0
  35. data/lib/generators/graphql/templates/mutation.erb +3 -1
  36. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  37. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  39. data/lib/generators/graphql/templates/node_type.erb +2 -0
  40. data/lib/generators/graphql/templates/object.erb +4 -2
  41. data/lib/generators/graphql/templates/query_type.erb +2 -0
  42. data/lib/generators/graphql/templates/scalar.erb +3 -1
  43. data/lib/generators/graphql/templates/schema.erb +19 -2
  44. data/lib/generators/graphql/templates/union.erb +4 -2
  45. data/lib/generators/graphql/type_generator.rb +46 -10
  46. data/lib/generators/graphql/union_generator.rb +5 -5
  47. data/lib/graphql/analysis/ast/analyzer.rb +7 -0
  48. data/lib/graphql/analysis/ast/field_usage.rb +55 -1
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
  51. data/lib/graphql/analysis/ast/query_depth.rb +7 -3
  52. data/lib/graphql/analysis/ast/visitor.rb +50 -42
  53. data/lib/graphql/analysis/ast.rb +26 -23
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/table.rb +4 -22
  56. data/lib/graphql/backtrace/trace.rb +93 -0
  57. data/lib/graphql/backtrace/tracer.rb +8 -6
  58. data/lib/graphql/backtrace.rb +3 -8
  59. data/lib/graphql/coercion_error.rb +1 -9
  60. data/lib/graphql/dataloader/async_dataloader.rb +85 -0
  61. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  62. data/lib/graphql/dataloader/request.rb +5 -0
  63. data/lib/graphql/dataloader/source.rb +120 -31
  64. data/lib/graphql/dataloader.rb +168 -142
  65. data/lib/graphql/date_encoding_error.rb +16 -0
  66. data/lib/graphql/dig.rb +1 -1
  67. data/lib/graphql/duration_encoding_error.rb +16 -0
  68. data/lib/graphql/execution/errors.rb +12 -81
  69. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
  71. data/lib/graphql/execution/interpreter/resolve.rb +32 -2
  72. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
  73. data/lib/graphql/execution/interpreter/runtime.rb +414 -341
  74. data/lib/graphql/execution/interpreter.rb +122 -80
  75. data/lib/graphql/execution/lazy.rb +11 -21
  76. data/lib/graphql/execution/lookahead.rb +125 -54
  77. data/lib/graphql/execution/multiplex.rb +4 -172
  78. data/lib/graphql/execution.rb +11 -4
  79. data/lib/graphql/integer_encoding_error.rb +18 -2
  80. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  81. data/lib/graphql/introspection/directive_type.rb +5 -3
  82. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  83. data/lib/graphql/introspection/entry_points.rb +11 -18
  84. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  85. data/lib/graphql/introspection/field_type.rb +3 -3
  86. data/lib/graphql/introspection/input_value_type.rb +10 -4
  87. data/lib/graphql/introspection/schema_type.rb +12 -5
  88. data/lib/graphql/introspection/type_type.rb +25 -12
  89. data/lib/graphql/introspection.rb +6 -2
  90. data/lib/graphql/language/block_string.rb +37 -25
  91. data/lib/graphql/language/definition_slice.rb +1 -1
  92. data/lib/graphql/language/document_from_schema_definition.rb +78 -65
  93. data/lib/graphql/language/lexer.rb +345 -1467
  94. data/lib/graphql/language/nodes.rb +145 -91
  95. data/lib/graphql/language/parser.rb +701 -1921
  96. data/lib/graphql/language/printer.rb +351 -155
  97. data/lib/graphql/language/sanitized_printer.rb +25 -27
  98. data/lib/graphql/language/static_visitor.rb +167 -0
  99. data/lib/graphql/language/token.rb +0 -4
  100. data/lib/graphql/language/visitor.rb +188 -141
  101. data/lib/graphql/language.rb +1 -0
  102. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  103. data/lib/graphql/name_validator.rb +0 -4
  104. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  105. data/lib/graphql/pagination/array_connection.rb +8 -6
  106. data/lib/graphql/pagination/connection.rb +61 -7
  107. data/lib/graphql/pagination/connections.rb +22 -23
  108. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  109. data/lib/graphql/pagination/relation_connection.rb +60 -28
  110. data/lib/graphql/query/context/scoped_context.rb +101 -0
  111. data/lib/graphql/query/context.rb +109 -189
  112. data/lib/graphql/query/input_validation_result.rb +10 -1
  113. data/lib/graphql/query/null_context.rb +14 -29
  114. data/lib/graphql/query/validation_pipeline.rb +15 -39
  115. data/lib/graphql/query/variable_validation_error.rb +2 -2
  116. data/lib/graphql/query/variables.rb +35 -17
  117. data/lib/graphql/query.rb +78 -65
  118. data/lib/graphql/railtie.rb +8 -109
  119. data/lib/graphql/rake_task/validate.rb +1 -1
  120. data/lib/graphql/rake_task.rb +30 -11
  121. data/lib/graphql/relay/range_add.rb +9 -16
  122. data/lib/graphql/relay.rb +0 -15
  123. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  124. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  125. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  126. data/lib/graphql/rubocop.rb +4 -0
  127. data/lib/graphql/schema/addition.rb +78 -45
  128. data/lib/graphql/schema/always_visible.rb +10 -0
  129. data/lib/graphql/schema/argument.rb +134 -80
  130. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  131. data/lib/graphql/schema/build_from_definition.rb +60 -38
  132. data/lib/graphql/schema/directive/feature.rb +1 -1
  133. data/lib/graphql/schema/directive/flagged.rb +2 -2
  134. data/lib/graphql/schema/directive/include.rb +1 -1
  135. data/lib/graphql/schema/directive/one_of.rb +24 -0
  136. data/lib/graphql/schema/directive/skip.rb +1 -1
  137. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  138. data/lib/graphql/schema/directive/transform.rb +2 -2
  139. data/lib/graphql/schema/directive.rb +33 -21
  140. data/lib/graphql/schema/enum.rb +93 -46
  141. data/lib/graphql/schema/enum_value.rb +4 -21
  142. data/lib/graphql/schema/field/connection_extension.rb +6 -16
  143. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  144. data/lib/graphql/schema/field.rb +432 -337
  145. data/lib/graphql/schema/field_extension.rb +86 -2
  146. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  147. data/lib/graphql/schema/finder.rb +5 -5
  148. data/lib/graphql/schema/has_single_input_argument.rb +156 -0
  149. data/lib/graphql/schema/input_object.rb +88 -90
  150. data/lib/graphql/schema/interface.rb +19 -59
  151. data/lib/graphql/schema/introspection_system.rb +6 -9
  152. data/lib/graphql/schema/late_bound_type.rb +8 -2
  153. data/lib/graphql/schema/list.rb +18 -7
  154. data/lib/graphql/schema/loader.rb +3 -3
  155. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
  156. data/lib/graphql/schema/member/build_type.rb +16 -13
  157. data/lib/graphql/schema/member/has_arguments.rb +288 -84
  158. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  159. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  160. data/lib/graphql/schema/member/has_directives.rb +81 -61
  161. data/lib/graphql/schema/member/has_fields.rb +149 -31
  162. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  163. data/lib/graphql/schema/member/has_validators.rb +32 -6
  164. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  165. data/lib/graphql/schema/member/scoped.rb +19 -0
  166. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  167. data/lib/graphql/schema/member/validates_input.rb +6 -6
  168. data/lib/graphql/schema/member.rb +1 -6
  169. data/lib/graphql/schema/mutation.rb +0 -9
  170. data/lib/graphql/schema/non_null.rb +7 -7
  171. data/lib/graphql/schema/object.rb +30 -119
  172. data/lib/graphql/schema/printer.rb +23 -25
  173. data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
  174. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  175. data/lib/graphql/schema/resolver.rb +101 -102
  176. data/lib/graphql/schema/scalar.rb +20 -21
  177. data/lib/graphql/schema/subscription.rb +45 -17
  178. data/lib/graphql/schema/timeout.rb +25 -29
  179. data/lib/graphql/schema/type_expression.rb +1 -1
  180. data/lib/graphql/schema/type_membership.rb +21 -4
  181. data/lib/graphql/schema/union.rb +15 -15
  182. data/lib/graphql/schema/unique_within_type.rb +1 -1
  183. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  184. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  185. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  186. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  187. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  188. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  189. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  190. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  191. data/lib/graphql/schema/validator.rb +35 -27
  192. data/lib/graphql/schema/warden.rb +259 -132
  193. data/lib/graphql/schema/wrapper.rb +0 -5
  194. data/lib/graphql/schema.rb +658 -989
  195. data/lib/graphql/static_validation/all_rules.rb +3 -1
  196. data/lib/graphql/static_validation/base_visitor.rb +14 -28
  197. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  198. data/lib/graphql/static_validation/error.rb +3 -1
  199. data/lib/graphql/static_validation/literal_validator.rb +21 -4
  200. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  201. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  202. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  203. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
  204. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  205. data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
  206. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  207. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  208. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  209. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  210. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  211. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  212. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
  213. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  214. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  215. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  216. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  217. data/lib/graphql/static_validation/validation_context.rb +16 -6
  218. data/lib/graphql/static_validation/validator.rb +11 -27
  219. data/lib/graphql/static_validation.rb +0 -3
  220. data/lib/graphql/string_encoding_error.rb +13 -3
  221. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
  222. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  223. data/lib/graphql/subscriptions/event.rb +75 -37
  224. data/lib/graphql/subscriptions/serialize.rb +25 -3
  225. data/lib/graphql/subscriptions.rb +59 -47
  226. data/lib/graphql/testing/helpers.rb +129 -0
  227. data/lib/graphql/testing.rb +2 -0
  228. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  229. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  230. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  231. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  232. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  233. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  234. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  235. data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
  236. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  237. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  238. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  239. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  240. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  241. data/lib/graphql/tracing/platform_trace.rb +118 -0
  242. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  243. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  244. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  245. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  246. data/lib/graphql/tracing/scout_trace.rb +72 -0
  247. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  248. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  249. data/lib/graphql/tracing/trace.rb +76 -0
  250. data/lib/graphql/tracing.rb +20 -41
  251. data/lib/graphql/type_kinds.rb +6 -3
  252. data/lib/graphql/types/big_int.rb +5 -1
  253. data/lib/graphql/types/int.rb +1 -1
  254. data/lib/graphql/types/iso_8601_date.rb +17 -6
  255. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  256. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  257. data/lib/graphql/types/relay/base_connection.rb +16 -6
  258. data/lib/graphql/types/relay/connection_behaviors.rb +82 -32
  259. data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
  260. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  261. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  262. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  263. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  264. data/lib/graphql/types/relay.rb +0 -3
  265. data/lib/graphql/types/string.rb +2 -2
  266. data/lib/graphql/types.rb +1 -0
  267. data/lib/graphql/unauthorized_error.rb +1 -1
  268. data/lib/graphql/version.rb +1 -1
  269. data/lib/graphql.rb +33 -95
  270. data/readme.md +13 -6
  271. metadata +102 -185
  272. data/lib/graphql/analysis/analyze_query.rb +0 -98
  273. data/lib/graphql/analysis/field_usage.rb +0 -45
  274. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  275. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  276. data/lib/graphql/analysis/query_complexity.rb +0 -88
  277. data/lib/graphql/analysis/query_depth.rb +0 -43
  278. data/lib/graphql/analysis/reducer_state.rb +0 -48
  279. data/lib/graphql/argument.rb +0 -131
  280. data/lib/graphql/authorization.rb +0 -82
  281. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  282. data/lib/graphql/backwards_compatibility.rb +0 -61
  283. data/lib/graphql/base_type.rb +0 -230
  284. data/lib/graphql/boolean_type.rb +0 -2
  285. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  286. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  287. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  288. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  289. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  290. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  291. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  292. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  293. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  294. data/lib/graphql/compatibility.rb +0 -5
  295. data/lib/graphql/define/assign_argument.rb +0 -12
  296. data/lib/graphql/define/assign_connection.rb +0 -13
  297. data/lib/graphql/define/assign_enum_value.rb +0 -18
  298. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  299. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  300. data/lib/graphql/define/assign_object_field.rb +0 -42
  301. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  302. data/lib/graphql/define/instance_definable.rb +0 -240
  303. data/lib/graphql/define/no_definition_error.rb +0 -7
  304. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  305. data/lib/graphql/define/type_definer.rb +0 -31
  306. data/lib/graphql/define.rb +0 -31
  307. data/lib/graphql/deprecated_dsl.rb +0 -47
  308. data/lib/graphql/deprecation.rb +0 -13
  309. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  310. data/lib/graphql/directive/include_directive.rb +0 -2
  311. data/lib/graphql/directive/skip_directive.rb +0 -2
  312. data/lib/graphql/directive.rb +0 -111
  313. data/lib/graphql/enum_type.rb +0 -129
  314. data/lib/graphql/execution/execute.rb +0 -333
  315. data/lib/graphql/execution/flatten.rb +0 -40
  316. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  317. data/lib/graphql/execution/typecast.rb +0 -50
  318. data/lib/graphql/field/resolve.rb +0 -59
  319. data/lib/graphql/field.rb +0 -226
  320. data/lib/graphql/filter.rb +0 -53
  321. data/lib/graphql/float_type.rb +0 -2
  322. data/lib/graphql/function.rb +0 -128
  323. data/lib/graphql/id_type.rb +0 -2
  324. data/lib/graphql/input_object_type.rb +0 -138
  325. data/lib/graphql/int_type.rb +0 -2
  326. data/lib/graphql/interface_type.rb +0 -72
  327. data/lib/graphql/internal_representation/document.rb +0 -27
  328. data/lib/graphql/internal_representation/node.rb +0 -206
  329. data/lib/graphql/internal_representation/print.rb +0 -51
  330. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  331. data/lib/graphql/internal_representation/scope.rb +0 -88
  332. data/lib/graphql/internal_representation/visit.rb +0 -36
  333. data/lib/graphql/internal_representation.rb +0 -7
  334. data/lib/graphql/language/lexer.rl +0 -262
  335. data/lib/graphql/language/parser.y +0 -543
  336. data/lib/graphql/list_type.rb +0 -80
  337. data/lib/graphql/non_null_type.rb +0 -71
  338. data/lib/graphql/object_type.rb +0 -130
  339. data/lib/graphql/query/arguments.rb +0 -189
  340. data/lib/graphql/query/arguments_cache.rb +0 -24
  341. data/lib/graphql/query/executor.rb +0 -52
  342. data/lib/graphql/query/literal_input.rb +0 -136
  343. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  344. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  345. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  346. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  347. data/lib/graphql/query/serial_execution.rb +0 -40
  348. data/lib/graphql/relay/array_connection.rb +0 -83
  349. data/lib/graphql/relay/base_connection.rb +0 -189
  350. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  351. data/lib/graphql/relay/connection_resolve.rb +0 -43
  352. data/lib/graphql/relay/connection_type.rb +0 -41
  353. data/lib/graphql/relay/edge.rb +0 -27
  354. data/lib/graphql/relay/edge_type.rb +0 -19
  355. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  356. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  357. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  358. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  359. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  360. data/lib/graphql/relay/mutation/result.rb +0 -38
  361. data/lib/graphql/relay/mutation.rb +0 -106
  362. data/lib/graphql/relay/node.rb +0 -39
  363. data/lib/graphql/relay/page_info.rb +0 -7
  364. data/lib/graphql/relay/relation_connection.rb +0 -188
  365. data/lib/graphql/relay/type_extensions.rb +0 -32
  366. data/lib/graphql/scalar_type.rb +0 -91
  367. data/lib/graphql/schema/base_64_bp.rb +0 -26
  368. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  369. data/lib/graphql/schema/default_parse_error.rb +0 -10
  370. data/lib/graphql/schema/default_type_error.rb +0 -17
  371. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  372. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  373. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  374. data/lib/graphql/schema/middleware_chain.rb +0 -82
  375. data/lib/graphql/schema/possible_types.rb +0 -44
  376. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  377. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  378. data/lib/graphql/schema/traversal.rb +0 -228
  379. data/lib/graphql/schema/validation.rb +0 -313
  380. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  381. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  382. data/lib/graphql/static_validation/type_stack.rb +0 -216
  383. data/lib/graphql/string_type.rb +0 -2
  384. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  385. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  386. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  387. data/lib/graphql/types/relay/default_relay.rb +0 -27
  388. data/lib/graphql/types/relay/node_field.rb +0 -25
  389. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  390. data/lib/graphql/union_type.rb +0 -115
  391. data/lib/graphql/upgrader/member.rb +0 -937
  392. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -5,7 +5,7 @@ module GraphQL
5
5
  module AST
6
6
  class QueryComplexity < Analyzer
7
7
  # State for the query complexity calculation:
8
- # - `complexities_on_type` holds complexity scores for each type in an IRep node
8
+ # - `complexities_on_type` holds complexity scores for each type
9
9
  def initialize(query)
10
10
  super
11
11
  @complexities_on_type_by_query = {}
@@ -16,50 +16,33 @@ module GraphQL
16
16
  max_possible_complexity
17
17
  end
18
18
 
19
- class ScopedTypeComplexity
20
- # A single proc for {#scoped_children} hashes. Use this to avoid repeated allocations,
21
- # since the lexical binding isn't important.
22
- HASH_CHILDREN = ->(h, k) { h[k] = {} }
19
+ # ScopedTypeComplexity models a tree of GraphQL types mapped to inner selections, ie:
20
+ # Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>
21
+ class ScopedTypeComplexity < Hash
22
+ # A proc for defaulting empty namespace requests as a new scope hash.
23
+ DEFAULT_PROC = ->(h, k) { h[k] = {} }
23
24
 
24
25
  attr_reader :field_definition, :response_path, :query
25
26
 
26
- # @param node [Language::Nodes::Field] The AST node; used for providing argument values when necessary
27
+ # @param parent_type [Class] The owner of `field_definition`
27
28
  # @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
28
29
  # @param query [GraphQL::Query] Used for `query.possible_types`
29
30
  # @param response_path [Array<String>] The path to the response key for the field
30
- def initialize(node, field_definition, query, response_path)
31
- @node = node
31
+ # @return [Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>]
32
+ def initialize(parent_type, field_definition, query, response_path)
33
+ super(&DEFAULT_PROC)
34
+ @parent_type = parent_type
32
35
  @field_definition = field_definition
33
36
  @query = query
34
37
  @response_path = response_path
35
- @scoped_children = nil
38
+ @nodes = []
36
39
  end
37
40
 
38
- # Returns true if this field has no selections, ie, it's a scalar.
39
- # We need a quick way to check whether we should continue traversing.
40
- def terminal?
41
- @scoped_children.nil?
42
- end
43
-
44
- # This value is only calculated when asked for to avoid needless hash allocations.
45
- # Also, if it's never asked for, we determine that this scope complexity
46
- # is a scalar field ({#terminal?}).
47
- # @return [Hash<Hash<Class => ScopedTypeComplexity>]
48
- def scoped_children
49
- @scoped_children ||= Hash.new(&HASH_CHILDREN)
50
- end
41
+ # @return [Array<GraphQL::Language::Nodes::Field>]
42
+ attr_reader :nodes
51
43
 
52
44
  def own_complexity(child_complexity)
53
- defined_complexity = @field_definition.complexity
54
- case defined_complexity
55
- when Proc
56
- arguments = @query.arguments_for(@node, @field_definition)
57
- defined_complexity.call(@query.context, arguments.keyword_arguments, child_complexity)
58
- when Numeric
59
- defined_complexity + child_complexity
60
- else
61
- raise("Invalid complexity: #{defined_complexity.inspect} on #{@field_definition.name}")
62
- end
45
+ @field_definition.calculate_complexity(query: @query, nodes: @nodes, child_complexity: child_complexity)
63
46
  end
64
47
  end
65
48
 
@@ -70,18 +53,14 @@ module GraphQL
70
53
  return if visitor.skipping?
71
54
  parent_type = visitor.parent_type_definition
72
55
  field_key = node.alias || node.name
73
- # Find the complexity calculation for this field --
74
- # if we're re-entering a selection, we'll already have one.
75
- # Otherwise, make a new one and store it.
76
- #
77
- # `node` and `visitor.field_definition` may appear from a cache,
78
- # but I think that's ok. If the arguments _didn't_ match,
79
- # then the query would have been rejected as invalid.
80
- complexities_on_type = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
81
-
82
- complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(node, visitor.field_definition, visitor.query, visitor.response_path)
83
- # Push it on the stack.
84
- complexities_on_type.push(complexity)
56
+
57
+ # Find or create a complexity scope stack for this query.
58
+ scopes_stack = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
59
+
60
+ # Find or create the complexity costing node for this field.
61
+ scope = scopes_stack.last[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path)
62
+ scope.nodes.push(node)
63
+ scopes_stack.push(scope)
85
64
  end
86
65
 
87
66
  def on_leave_field(node, parent, visitor)
@@ -89,89 +68,61 @@ module GraphQL
89
68
  # we'll visit them when we hit the spreads instead
90
69
  return if visitor.visiting_fragment_definition?
91
70
  return if visitor.skipping?
92
- complexities_on_type = @complexities_on_type_by_query[visitor.query]
93
- complexities_on_type.pop
71
+ scopes_stack = @complexities_on_type_by_query[visitor.query]
72
+ scopes_stack.pop
94
73
  end
95
74
 
96
75
  private
97
76
 
98
77
  # @return [Integer]
99
78
  def max_possible_complexity
100
- @complexities_on_type_by_query.reduce(0) do |total, (query, complexities_on_type)|
101
- root_complexity = complexities_on_type.last
102
- # Use this entry point to calculate the total complexity
103
- total_complexity_for_query = merged_max_complexity_for_scopes(query, [root_complexity.scoped_children])
104
- total + total_complexity_for_query
79
+ @complexities_on_type_by_query.reduce(0) do |total, (query, scopes_stack)|
80
+ total + merged_max_complexity_for_scopes(query, [scopes_stack.first])
105
81
  end
106
82
  end
107
83
 
108
84
  # @param query [GraphQL::Query] Used for `query.possible_types`
109
- # @param scoped_children_hashes [Array<Hash>] Array of scoped children hashes
85
+ # @param scopes [Array<ScopedTypeComplexity>] Array of scoped type complexities
110
86
  # @return [Integer]
111
- def merged_max_complexity_for_scopes(query, scoped_children_hashes)
112
- # Figure out what scopes are possible here.
87
+ def merged_max_complexity_for_scopes(query, scopes)
88
+ # Aggregate a set of all possible scope types encountered (scope keys).
113
89
  # Use a hash, but ignore the values; it's just a fast way to work with the keys.
114
- all_scopes = {}
115
- scoped_children_hashes.each do |h|
116
- all_scopes.merge!(h)
90
+ possible_scope_types = scopes.each_with_object({}) do |scope, memo|
91
+ memo.merge!(scope)
117
92
  end
118
93
 
119
- # If an abstract scope is present, but _all_ of its concrete types
120
- # are also in the list, remove it from the list of scopes to check,
121
- # because every possible type is covered by a concrete type.
122
- # (That is, there are no remainder types to check.)
123
- prev_keys = all_scopes.keys
124
- prev_keys.each do |scope|
125
- next unless scope.kind.abstract?
126
-
127
- missing_concrete_types = query.possible_types(scope).select { |t| !all_scopes.key?(t) }
128
- # This concrete type is possible _only_ as a member of the abstract type.
129
- # So, attribute to it the complexity which belongs to the abstract type.
130
- missing_concrete_types.each do |concrete_scope|
131
- all_scopes[concrete_scope] = all_scopes[scope]
94
+ # Expand abstract scope types into their concrete implementations;
95
+ # overlapping abstracts coalesce through their intersecting types.
96
+ possible_scope_types.keys.each do |possible_scope_type|
97
+ next unless possible_scope_type.kind.abstract?
98
+
99
+ query.possible_types(possible_scope_type).each do |impl_type|
100
+ possible_scope_types[impl_type] ||= true
132
101
  end
133
- all_scopes.delete(scope)
102
+ possible_scope_types.delete(possible_scope_type)
134
103
  end
135
104
 
136
- # This will hold `{ type => int }` pairs, one for each possible branch
137
- complexity_by_scope = {}
138
-
139
- # For each scope,
140
- # find the lexical selections that might apply to it,
141
- # and gather them together into an array.
142
- # Then, treat the set of selection hashes
143
- # as a set and calculate the complexity for them as a unit
144
- all_scopes.each do |scope, _|
145
- # These will be the selections on `scope`
146
- children_for_scope = []
147
- scoped_children_hashes.each do |sc_h|
148
- sc_h.each do |inner_scope, children_hash|
149
- if applies_to?(query, scope, inner_scope)
150
- children_for_scope << children_hash
151
- end
105
+ # Aggregate the lexical selections that may apply to each possible type,
106
+ # and then return the maximum cost among possible typed selections.
107
+ possible_scope_types.each_key.reduce(0) do |max, possible_scope_type|
108
+ # Collect inner selections from all scopes that intersect with this possible type.
109
+ all_inner_selections = scopes.each_with_object([]) do |scope, memo|
110
+ scope.each do |scope_type, inner_selections|
111
+ memo << inner_selections if types_intersect?(query, scope_type, possible_scope_type)
152
112
  end
153
113
  end
154
114
 
155
- # Calculate the complexity for `scope`, merging all
156
- # possible lexical branches.
157
- complexity_value = merged_max_complexity(query, children_for_scope)
158
- complexity_by_scope[scope] = complexity_value
115
+ # Find the maximum complexity for the scope type among possible lexical branches.
116
+ complexity = merged_max_complexity(query, all_inner_selections)
117
+ complexity > max ? complexity : max
159
118
  end
160
-
161
- # Return the max complexity among all scopes
162
- complexity_by_scope.each_value.max
163
119
  end
164
120
 
165
- def applies_to?(query, left_scope, right_scope)
166
- if left_scope == right_scope
167
- # This can happen when several branches are being analyzed together
168
- true
169
- else
170
- # Check if these two scopes have _any_ types in common.
171
- possible_right_types = query.possible_types(right_scope)
172
- possible_left_types = query.possible_types(left_scope)
173
- !(possible_right_types & possible_left_types).empty?
174
- end
121
+ def types_intersect?(query, a, b)
122
+ return true if a == b
123
+
124
+ a_types = query.possible_types(a)
125
+ query.possible_types(b).any? { |t| a_types.include?(t) }
175
126
  end
176
127
 
177
128
  # A hook which is called whenever a field's max complexity is calculated.
@@ -183,50 +134,47 @@ module GraphQL
183
134
  def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
184
135
  end
185
136
 
186
- # @param children_for_scope [Array<Hash>] An array of `scoped_children[scope]` hashes
187
- # (`{field_key => complexity}`)
188
- # @return [Integer] Complexity value for all these selections in the current scope
189
- def merged_max_complexity(query, children_for_scope)
190
- all_keys = []
191
- children_for_scope.each do |c|
192
- all_keys.concat(c.keys)
137
+ # @param inner_selections [Array<Hash<String, ScopedTypeComplexity>>] Field selections for a scope
138
+ # @return [Integer] Total complexity value for all these selections in the parent scope
139
+ def merged_max_complexity(query, inner_selections)
140
+ # Aggregate a set of all unique field selection keys across all scopes.
141
+ # Use a hash, but ignore the values; it's just a fast way to work with the keys.
142
+ unique_field_keys = inner_selections.each_with_object({}) do |inner_selection, memo|
143
+ memo.merge!(inner_selection)
193
144
  end
194
- all_keys.uniq!
195
- complexity_for_keys = {}
196
-
197
- all_keys.each do |child_key|
198
- scoped_children_for_key = nil
199
- complexity_for_key = nil
200
- children_for_scope.each do |children_hash|
201
- next unless children_hash.key?(child_key)
202
-
203
- complexity_for_key = children_hash[child_key]
204
- if complexity_for_key.terminal?
205
- # Assume that all terminals would return the same complexity
206
- # Since it's a terminal, its child complexity is zero.
207
- complexity = complexity_for_key.own_complexity(0)
208
- complexity_for_keys[child_key] = complexity
209
-
210
- field_complexity(complexity_for_key, max_complexity: complexity, child_complexity: nil)
145
+
146
+ # Add up the total cost for each unique field name's coalesced selections
147
+ unique_field_keys.each_key.reduce(0) do |total, field_key|
148
+ composite_scopes = nil
149
+ field_cost = 0
150
+
151
+ # Collect composite selection scopes for further aggregation,
152
+ # leaf selections report their costs directly.
153
+ inner_selections.each do |inner_selection|
154
+ child_scope = inner_selection[field_key]
155
+ next unless child_scope
156
+
157
+ # Empty child scopes are leaf nodes with zero child complexity.
158
+ if child_scope.empty?
159
+ field_cost = child_scope.own_complexity(0)
160
+ field_complexity(child_scope, max_complexity: field_cost, child_complexity: nil)
211
161
  else
212
- scoped_children_for_key ||= []
213
- scoped_children_for_key << complexity_for_key.scoped_children
162
+ composite_scopes ||= []
163
+ composite_scopes << child_scope
214
164
  end
215
165
  end
216
166
 
217
- next unless scoped_children_for_key
167
+ if composite_scopes
168
+ child_complexity = merged_max_complexity_for_scopes(query, composite_scopes)
218
169
 
219
- child_complexity = merged_max_complexity_for_scopes(query, scoped_children_for_key)
220
- # This is the _last_ one we visited; assume it's representative.
221
- max_complexity = complexity_for_key.own_complexity(child_complexity)
222
-
223
- field_complexity(complexity_for_key, max_complexity: max_complexity, child_complexity: child_complexity)
170
+ # This is the last composite scope visited; assume it's representative (for backwards compatibility).
171
+ # Note: it would be more correct to score each composite scope and use the maximum possibility.
172
+ field_cost = composite_scopes.last.own_complexity(child_complexity)
173
+ field_complexity(composite_scopes.last, max_complexity: field_cost, child_complexity: child_complexity)
174
+ end
224
175
 
225
- complexity_for_keys[child_key] = max_complexity
176
+ total + field_cost
226
177
  end
227
-
228
- # Calculate the child complexity by summing the complexity of all selections
229
- complexity_for_keys.each_value.inject(0, &:+)
230
178
  end
231
179
  end
232
180
  end
@@ -15,7 +15,6 @@ module GraphQL
15
15
  # # In your Schema file:
16
16
  #
17
17
  # class MySchema < GraphQL::Schema
18
- # use GraphQL::Analysis::AST
19
18
  # query_analyzer LogQueryDepth
20
19
  # end
21
20
  #
@@ -29,17 +28,22 @@ module GraphQL
29
28
  def initialize(query)
30
29
  @max_depth = 0
31
30
  @current_depth = 0
31
+ @count_introspection_fields = query.schema.count_introspection_fields
32
32
  super
33
33
  end
34
34
 
35
35
  def on_enter_field(node, parent, visitor)
36
- return if visitor.skipping? || visitor.visiting_fragment_definition?
36
+ return if visitor.skipping? ||
37
+ visitor.visiting_fragment_definition? ||
38
+ (@count_introspection_fields == false && visitor.field_definition.introspection?)
37
39
 
38
40
  @current_depth += 1
39
41
  end
40
42
 
41
43
  def on_leave_field(node, parent, visitor)
42
- return if visitor.skipping? || visitor.visiting_fragment_definition?
44
+ return if visitor.skipping? ||
45
+ visitor.visiting_fragment_definition? ||
46
+ (@count_introspection_fields == false && visitor.field_definition.introspection?)
43
47
 
44
48
  if @max_depth < @current_depth
45
49
  @max_depth = @current_depth
@@ -5,12 +5,12 @@ module GraphQL
5
5
  # Depth first traversal through a query AST, calling AST analyzers
6
6
  # along the way.
7
7
  #
8
- # The visitor is a special case of GraphQL::Language::Visitor, visiting
8
+ # The visitor is a special case of GraphQL::Language::StaticVisitor, visiting
9
9
  # only the selected operation, providing helpers for common use cases such
10
10
  # as skipped fields and visiting fragment spreads.
11
11
  #
12
12
  # @see {GraphQL::Analysis::AST::Analyzer} AST Analyzers for queries
13
- class Visitor < GraphQL::Language::Visitor
13
+ class Visitor < GraphQL::Language::StaticVisitor
14
14
  def initialize(query:, analyzers:)
15
15
  @analyzers = analyzers
16
16
  @path = []
@@ -43,7 +43,7 @@ module GraphQL
43
43
 
44
44
  # Visit Helpers
45
45
 
46
- # @return [GraphQL::Query::Arguments] Arguments for this node, merging default values, literal values and query variables
46
+ # @return [GraphQL::Execution::Interpreter::Arguments] Arguments for this node, merging default values, literal values and query variables
47
47
  # @see {GraphQL::Query#arguments_for}
48
48
  def arguments_for(ast_node, field_definition)
49
49
  @query.arguments_for(ast_node, field_definition)
@@ -65,14 +65,41 @@ module GraphQL
65
65
  end
66
66
 
67
67
  # Visitor Hooks
68
+ [
69
+ :operation_definition, :fragment_definition,
70
+ :inline_fragment, :field, :directive, :argument, :fragment_spread
71
+ ].each do |node_type|
72
+ module_eval <<-RUBY, __FILE__, __LINE__
73
+ def call_on_enter_#{node_type}(node, parent)
74
+ @analyzers.each do |a|
75
+ begin
76
+ a.on_enter_#{node_type}(node, parent, self)
77
+ rescue AnalysisError => err
78
+ @rescued_errors << err
79
+ end
80
+ end
81
+ end
82
+
83
+ def call_on_leave_#{node_type}(node, parent)
84
+ @analyzers.each do |a|
85
+ begin
86
+ a.on_leave_#{node_type}(node, parent, self)
87
+ rescue AnalysisError => err
88
+ @rescued_errors << err
89
+ end
90
+ end
91
+ end
92
+
93
+ RUBY
94
+ end
68
95
 
69
96
  def on_operation_definition(node, parent)
70
97
  object_type = @schema.root_type_for_operation(node.operation_type)
71
98
  @object_types.push(object_type)
72
99
  @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
73
- call_analyzers(:on_enter_operation_definition, node, parent)
100
+ call_on_enter_operation_definition(node, parent)
74
101
  super
75
- call_analyzers(:on_leave_operation_definition, node, parent)
102
+ call_on_leave_operation_definition(node, parent)
76
103
  @object_types.pop
77
104
  @path.pop
78
105
  end
@@ -81,26 +108,27 @@ module GraphQL
81
108
  on_fragment_with_type(node) do
82
109
  @path.push("fragment #{node.name}")
83
110
  @in_fragment_def = false
84
- call_analyzers(:on_enter_fragment_definition, node, parent)
111
+ call_on_enter_fragment_definition(node, parent)
85
112
  super
86
113
  @in_fragment_def = false
87
- call_analyzers(:on_leave_fragment_definition, node, parent)
114
+ call_on_leave_fragment_definition(node, parent)
88
115
  end
89
116
  end
90
117
 
91
118
  def on_inline_fragment(node, parent)
92
119
  on_fragment_with_type(node) do
93
120
  @path.push("...#{node.type ? " on #{node.type.name}" : ""}")
94
- call_analyzers(:on_enter_inline_fragment, node, parent)
121
+ call_on_enter_inline_fragment(node, parent)
95
122
  super
96
- call_analyzers(:on_leave_inline_fragment, node, parent)
123
+ call_on_leave_inline_fragment(node, parent)
97
124
  end
98
125
  end
99
126
 
100
127
  def on_field(node, parent)
101
128
  @response_path.push(node.alias || node.name)
102
129
  parent_type = @object_types.last
103
- field_definition = @schema.get_field(parent_type, node.name)
130
+ # This could be nil if the previous field wasn't found:
131
+ field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context)
104
132
  @field_definitions.push(field_definition)
105
133
  if !field_definition.nil?
106
134
  next_object_type = field_definition.type.unwrap
@@ -113,12 +141,10 @@ module GraphQL
113
141
  @skipping = @skip_stack.last || skip?(node)
114
142
  @skip_stack << @skipping
115
143
 
116
- call_analyzers(:on_enter_field, node, parent)
144
+ call_on_enter_field(node, parent)
117
145
  super
118
-
119
146
  @skipping = @skip_stack.pop
120
-
121
- call_analyzers(:on_leave_field, node, parent)
147
+ call_on_leave_field(node, parent)
122
148
  @response_path.pop
123
149
  @field_definitions.pop
124
150
  @object_types.pop
@@ -128,9 +154,9 @@ module GraphQL
128
154
  def on_directive(node, parent)
129
155
  directive_defn = @schema.directives[node.name]
130
156
  @directive_definitions.push(directive_defn)
131
- call_analyzers(:on_enter_directive, node, parent)
157
+ call_on_enter_directive(node, parent)
132
158
  super
133
- call_analyzers(:on_leave_directive, node, parent)
159
+ call_on_leave_directive(node, parent)
134
160
  @directive_definitions.pop
135
161
  end
136
162
 
@@ -138,43 +164,37 @@ module GraphQL
138
164
  argument_defn = if (arg = @argument_definitions.last)
139
165
  arg_type = arg.type.unwrap
140
166
  if arg_type.kind.input_object?
141
- arg_type.arguments[node.name]
167
+ arg_type.get_argument(node.name, @query.context)
142
168
  else
143
169
  nil
144
170
  end
145
171
  elsif (directive_defn = @directive_definitions.last)
146
- directive_defn.arguments[node.name]
172
+ directive_defn.get_argument(node.name, @query.context)
147
173
  elsif (field_defn = @field_definitions.last)
148
- field_defn.arguments[node.name]
174
+ field_defn.get_argument(node.name, @query.context)
149
175
  else
150
176
  nil
151
177
  end
152
178
 
153
179
  @argument_definitions.push(argument_defn)
154
180
  @path.push(node.name)
155
- call_analyzers(:on_enter_argument, node, parent)
181
+ call_on_enter_argument(node, parent)
156
182
  super
157
- call_analyzers(:on_leave_argument, node, parent)
183
+ call_on_leave_argument(node, parent)
158
184
  @argument_definitions.pop
159
185
  @path.pop
160
186
  end
161
187
 
162
188
  def on_fragment_spread(node, parent)
163
189
  @path.push("... #{node.name}")
164
- call_analyzers(:on_enter_fragment_spread, node, parent)
190
+ call_on_enter_fragment_spread(node, parent)
165
191
  enter_fragment_spread_inline(node)
166
192
  super
167
193
  leave_fragment_spread_inline(node)
168
- call_analyzers(:on_leave_fragment_spread, node, parent)
194
+ call_on_leave_fragment_spread(node, parent)
169
195
  @path.pop
170
196
  end
171
197
 
172
- def on_abstract_node(node, parent)
173
- call_analyzers(:on_enter_abstract_node, node, parent)
174
- super
175
- call_analyzers(:on_leave_abstract_node, node, parent)
176
- end
177
-
178
198
  # @return [GraphQL::BaseType] The current object type
179
199
  def type_definition
180
200
  @object_types.last
@@ -225,9 +245,7 @@ module GraphQL
225
245
 
226
246
  object_types << object_type
227
247
 
228
- fragment_def.selections.each do |selection|
229
- visit_node(selection, fragment_def)
230
- end
248
+ on_fragment_definition_children(fragment_def)
231
249
  end
232
250
 
233
251
  # Visit a fragment spread inline instead of visiting the definition
@@ -241,16 +259,6 @@ module GraphQL
241
259
  dir.any? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
242
260
  end
243
261
 
244
- def call_analyzers(method, node, parent)
245
- @analyzers.each do |analyzer|
246
- begin
247
- analyzer.public_send(method, node, parent, self)
248
- rescue AnalysisError => err
249
- @rescued_errors << err
250
- end
251
- end
252
- end
253
-
254
262
  def on_fragment_with_type(node)
255
263
  object_type = if node.type
256
264
  @query.warden.get_type(node.type.name)
@@ -6,21 +6,12 @@ require "graphql/analysis/ast/query_complexity"
6
6
  require "graphql/analysis/ast/max_query_complexity"
7
7
  require "graphql/analysis/ast/query_depth"
8
8
  require "graphql/analysis/ast/max_query_depth"
9
+ require "timeout"
9
10
 
10
11
  module GraphQL
11
12
  module Analysis
12
13
  module AST
13
14
  module_function
14
-
15
- def use(schema_class)
16
- if schema_class.analysis_engine == self
17
- definition_line = caller(2, 1).first
18
- GraphQL::Deprecation.warn("GraphQL::Analysis::AST is now the default; remove `use GraphQL::Analysis::AST` from the schema definition (#{definition_line})")
19
- else
20
- schema_class.analysis_engine = self
21
- end
22
- end
23
-
24
15
  # Analyze a multiplex, and all queries within.
25
16
  # Multiplex analyzers are ran for all queries, keeping state.
26
17
  # Query analyzers are ran per query, without carrying state between queries.
@@ -31,7 +22,7 @@ module GraphQL
31
22
  def analyze_multiplex(multiplex, analyzers)
32
23
  multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
33
24
 
34
- multiplex.trace("analyze_multiplex", { multiplex: multiplex }) do
25
+ multiplex.current_trace.analyze_multiplex(multiplex: multiplex) do
35
26
  query_results = multiplex.queries.map do |query|
36
27
  if query.valid?
37
28
  analyze_query(
@@ -58,33 +49,45 @@ module GraphQL
58
49
  # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
59
50
  # @return [Array<Any>] Results from those analyzers
60
51
  def analyze_query(query, analyzers, multiplex_analyzers: [])
61
- query.trace("analyze_query", { query: query }) do
52
+ query.current_trace.analyze_query(query: query) do
62
53
  query_analyzers = analyzers
63
54
  .map { |analyzer| analyzer.new(query) }
64
- .select { |analyzer| analyzer.analyze? }
55
+ .tap { _1.select!(&:analyze?) }
65
56
 
66
57
  analyzers_to_run = query_analyzers + multiplex_analyzers
67
58
  if analyzers_to_run.any?
68
- visitor = GraphQL::Analysis::AST::Visitor.new(
69
- query: query,
70
- analyzers: analyzers_to_run
71
- )
72
59
 
73
- visitor.visit
60
+ analyzers_to_run.select!(&:visit?)
61
+ if analyzers_to_run.any?
62
+ visitor = GraphQL::Analysis::AST::Visitor.new(
63
+ query: query,
64
+ analyzers: analyzers_to_run
65
+ )
74
66
 
75
- if visitor.rescued_errors.any?
76
- visitor.rescued_errors
77
- else
78
- query_analyzers.map(&:result)
67
+ # `nil` or `0` causes no timeout
68
+ Timeout::timeout(query.validate_timeout_remaining) do
69
+ visitor.visit
70
+ end
71
+
72
+ if visitor.rescued_errors.any?
73
+ return visitor.rescued_errors
74
+ end
79
75
  end
76
+
77
+ query_analyzers.map(&:result)
80
78
  else
81
79
  []
82
80
  end
83
81
  end
82
+ rescue Timeout::Error
83
+ [GraphQL::AnalysisError.new("Timeout on validation of query")]
84
+ rescue GraphQL::UnauthorizedError
85
+ # This error was raised during analysis and will be returned the client before execution
86
+ []
84
87
  end
85
88
 
86
89
  def analysis_errors(results)
87
- results.flatten.select { |r| r.is_a?(GraphQL::AnalysisError) }
90
+ results.flatten.tap { _1.select! { |r| r.is_a?(GraphQL::AnalysisError) } }
88
91
  end
89
92
  end
90
93
  end
@@ -1,9 +1,2 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/analysis/ast"
3
- require "graphql/analysis/max_query_complexity"
4
- require "graphql/analysis/max_query_depth"
5
- require "graphql/analysis/query_complexity"
6
- require "graphql/analysis/query_depth"
7
- require "graphql/analysis/reducer_state"
8
- require "graphql/analysis/analyze_query"
9
- require "graphql/analysis/field_usage"