graphql 1.12.12 → 2.2.14

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 (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
@@ -1,24 +1,17 @@
1
1
  # frozen_string_literal: true
2
+ require "logger"
2
3
  require "graphql/schema/addition"
4
+ require "graphql/schema/always_visible"
3
5
  require "graphql/schema/base_64_encoder"
4
- require "graphql/schema/catchall_middleware"
5
- require "graphql/schema/default_parse_error"
6
- require "graphql/schema/default_type_error"
7
6
  require "graphql/schema/find_inherited_value"
8
7
  require "graphql/schema/finder"
9
8
  require "graphql/schema/invalid_type_error"
10
9
  require "graphql/schema/introspection_system"
11
10
  require "graphql/schema/late_bound_type"
12
- require "graphql/schema/middleware_chain"
13
11
  require "graphql/schema/null_mask"
14
- require "graphql/schema/possible_types"
15
- require "graphql/schema/rescue_middleware"
16
12
  require "graphql/schema/timeout"
17
- require "graphql/schema/timeout_middleware"
18
- require "graphql/schema/traversal"
19
13
  require "graphql/schema/type_expression"
20
14
  require "graphql/schema/unique_within_type"
21
- require "graphql/schema/validation"
22
15
  require "graphql/schema/warden"
23
16
  require "graphql/schema/build_from_definition"
24
17
 
@@ -40,14 +33,17 @@ require "graphql/schema/union"
40
33
  require "graphql/schema/directive"
41
34
  require "graphql/schema/directive/deprecated"
42
35
  require "graphql/schema/directive/include"
36
+ require "graphql/schema/directive/one_of"
43
37
  require "graphql/schema/directive/skip"
44
38
  require "graphql/schema/directive/feature"
45
39
  require "graphql/schema/directive/flagged"
46
40
  require "graphql/schema/directive/transform"
41
+ require "graphql/schema/directive/specified_by"
47
42
  require "graphql/schema/type_membership"
48
43
 
49
44
  require "graphql/schema/resolver"
50
45
  require "graphql/schema/mutation"
46
+ require "graphql/schema/has_single_input_argument"
51
47
  require "graphql/schema/relay_classic_mutation"
52
48
  require "graphql/schema/subscription"
53
49
 
@@ -67,10 +63,6 @@ module GraphQL
67
63
  # Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
68
64
  # (These configurations can be overridden by specific calls to {Schema#execute})
69
65
  #
70
- # Schemas can specify how queries should be executed against them.
71
- # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
72
- # each apply to corresponding root types.
73
- # #
74
66
  # @example defining a schema
75
67
  # class MySchema < GraphQL::Schema
76
68
  # query QueryType
@@ -79,16 +71,16 @@ module GraphQL
79
71
  # end
80
72
  #
81
73
  class Schema
82
- extend Forwardable
83
- extend GraphQL::Schema::Member::AcceptsDefinition
84
74
  extend GraphQL::Schema::Member::HasAstNode
85
- include GraphQL::Define::InstanceDefinable
86
- extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
87
75
  extend GraphQL::Schema::FindInheritedValue
88
76
 
89
- class DuplicateTypeNamesError < GraphQL::Error
90
- def initialize(type_name:, first_definition:, second_definition:, path:)
91
- super("Multiple definitions for `#{type_name}`. Previously found #{first_definition.inspect} (#{first_definition.class}), then found #{second_definition.inspect} (#{second_definition.class}) at #{path.join(".")}")
77
+ class DuplicateNamesError < GraphQL::Error
78
+ attr_reader :duplicated_name
79
+ def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
80
+ @duplicated_name = duplicated_name
81
+ super(
82
+ "Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
83
+ )
92
84
  end
93
85
  end
94
86
 
@@ -100,760 +92,169 @@ module GraphQL
100
92
  end
101
93
  end
102
94
 
103
- module LazyHandlingMethods
104
- # Call the given block at the right time, either:
105
- # - Right away, if `value` is not registered with `lazy_resolve`
106
- # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
107
- # @api private
108
- def after_lazy(value, &block)
109
- if lazy?(value)
110
- GraphQL::Execution::Lazy.new do
111
- result = sync_lazy(value)
112
- # The returned result might also be lazy, so check it, too
113
- after_lazy(result, &block)
114
- end
95
+ # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
96
+ class InvalidDocumentError < Error; end;
97
+
98
+ class << self
99
+ # Create schema with the result of an introspection query.
100
+ # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
101
+ # @return [Class<GraphQL::Schema>] the schema described by `input`
102
+ def from_introspection(introspection_result)
103
+ GraphQL::Schema::Loader.load(introspection_result)
104
+ end
105
+
106
+ # Create schema from an IDL schema or file containing an IDL definition.
107
+ # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
108
+ # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
109
+ # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
110
+ # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
111
+ # @return [Class] the schema described by `document`
112
+ def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
113
+ # If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
114
+ if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
115
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
116
+ self,
117
+ definition_or_path,
118
+ default_resolve: default_resolve,
119
+ parser: parser,
120
+ using: using,
121
+ )
115
122
  else
116
- yield(value) if block_given?
123
+ GraphQL::Schema::BuildFromDefinition.from_definition(
124
+ self,
125
+ definition_or_path,
126
+ default_resolve: default_resolve,
127
+ parser: parser,
128
+ using: using,
129
+ )
117
130
  end
118
131
  end
119
132
 
120
- # Override this method to handle lazy objects in a custom way.
121
- # @param value [Object] an instance of a class registered with {.lazy_resolve}
122
- # @return [Object] A GraphQL-ready (non-lazy) object
123
- # @api private
124
- def sync_lazy(value)
125
- lazy_method = lazy_method_name(value)
126
- if lazy_method
127
- synced_value = value.public_send(lazy_method)
128
- sync_lazy(synced_value)
129
- else
130
- value
131
- end
133
+ def deprecated_graphql_definition
134
+ graphql_definition(silence_deprecation_warning: true)
132
135
  end
133
136
 
134
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
135
- def lazy_method_name(obj)
136
- lazy_methods.get(obj)
137
+ # @return [GraphQL::Subscriptions]
138
+ def subscriptions(inherited: true)
139
+ defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
137
140
  end
138
141
 
139
- # @return [Boolean] True if this object should be lazily resolved
140
- def lazy?(obj)
141
- !!lazy_method_name(obj)
142
+ def subscriptions=(new_implementation)
143
+ @subscriptions = new_implementation
142
144
  end
143
145
 
144
- # Return a lazy if any of `maybe_lazies` are lazy,
145
- # otherwise, call the block eagerly and return the result.
146
- # @param maybe_lazies [Array]
147
- # @api private
148
- def after_any_lazies(maybe_lazies)
149
- if maybe_lazies.any? { |l| lazy?(l) }
150
- GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
151
- yield result
152
- end
146
+ # @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
147
+ def default_trace_mode(new_mode = nil)
148
+ if new_mode
149
+ @default_trace_mode = new_mode
150
+ elsif defined?(@default_trace_mode)
151
+ @default_trace_mode
152
+ elsif superclass.respond_to?(:default_trace_mode)
153
+ superclass.default_trace_mode
153
154
  else
154
- yield maybe_lazies
155
+ :default
155
156
  end
156
157
  end
157
- end
158
-
159
- include LazyHandlingMethods
160
- extend LazyHandlingMethods
161
-
162
- accepts_definitions \
163
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
164
- :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
165
- :orphan_types, :resolve_type, :type_error, :parse_error,
166
- :error_bubbling,
167
- :raise_definition_error,
168
- :object_from_id, :id_from_object,
169
- :default_mask,
170
- :cursor_encoder,
171
- # If these are given as classes, normalize them. Accept `nil` when building from string.
172
- query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
173
- mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
174
- subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
175
- disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
176
- disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
177
- disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
178
- directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
179
- directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
180
- instrument: ->(schema, type, instrumenter, after_built_ins: false) {
181
- if type == :field && after_built_ins
182
- type = :field_after_built_ins
183
- end
184
- schema.instrumenters[type] << instrumenter
185
- },
186
- query_analyzer: ->(schema, analyzer) {
187
- if analyzer == GraphQL::Authorization::Analyzer
188
- GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
189
- end
190
- schema.query_analyzers << analyzer
191
- },
192
- multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
193
- middleware: ->(schema, middleware) { schema.middleware << middleware },
194
- lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
195
- rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
196
- tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
197
-
198
- ensure_defined :introspection_system
199
-
200
- attr_accessor \
201
- :query, :mutation, :subscription,
202
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
203
- :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
204
- :orphan_types, :directives,
205
- :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
206
- :cursor_encoder,
207
- :ast_node,
208
- :raise_definition_error,
209
- :introspection_namespace,
210
- :analysis_engine
211
-
212
- # [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
213
- attr_accessor :error_bubbling
214
-
215
- # Single, long-lived instance of the provided subscriptions class, if there is one.
216
- # @return [GraphQL::Subscriptions]
217
- attr_accessor :subscriptions
218
-
219
- # @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
220
- attr_accessor :middleware
221
-
222
- # @return [<#call(member, ctx)>] A callable for filtering members of the schema
223
- # @see {Query.new} for query-specific filters with `except:`
224
- attr_accessor :default_mask
225
-
226
- # @see {GraphQL::Query::Context} The parent class of these classes
227
- # @return [Class] Instantiated for each query
228
- attr_accessor :context_class
229
-
230
- # [Boolean] True if this object disables the introspection entry point fields
231
- attr_accessor :disable_introspection_entry_points
232
-
233
- def disable_introspection_entry_points?
234
- !!@disable_introspection_entry_points
235
- end
236
-
237
- # [Boolean] True if this object disables the __schema introspection entry point field
238
- attr_accessor :disable_schema_introspection_entry_point
239
-
240
- def disable_schema_introspection_entry_point?
241
- !!@disable_schema_introspection_entry_point
242
- end
243
-
244
- # [Boolean] True if this object disables the __type introspection entry point field
245
- attr_accessor :disable_type_introspection_entry_point
246
-
247
- def disable_type_introspection_entry_point?
248
- !!@disable_type_introspection_entry_point
249
- end
250
-
251
- class << self
252
- attr_writer :default_execution_strategy
253
- end
254
-
255
- def default_filter
256
- GraphQL::Filter.new(except: default_mask)
257
- end
258
-
259
- # @return [Array<#trace(key, data)>] Tracers applied to every query
260
- # @see {Query#tracers} for query-specific tracers
261
- attr_reader :tracers
262
-
263
- DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
264
-
265
- attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
266
-
267
- def initialize
268
- @tracers = []
269
- @definition_error = nil
270
- @orphan_types = []
271
- @directives = {}
272
- self.class.default_directives.each do |name, dir|
273
- @directives[name] = dir.graphql_definition
274
- end
275
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
276
- @middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
277
- @query_analyzers = []
278
- @multiplex_analyzers = []
279
- @resolve_type_proc = nil
280
- @object_from_id_proc = nil
281
- @id_from_object_proc = nil
282
- @type_error_proc = DefaultTypeError
283
- @parse_error_proc = DefaultParseError
284
- @instrumenters = Hash.new { |h, k| h[k] = [] }
285
- @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
286
- @lazy_methods.set(GraphQL::Execution::Lazy, :value)
287
- @cursor_encoder = Base64Encoder
288
- # For schema instances, default to legacy runtime modules
289
- @analysis_engine = GraphQL::Analysis
290
- @query_execution_strategy = GraphQL::Execution::Execute
291
- @mutation_execution_strategy = GraphQL::Execution::Execute
292
- @subscription_execution_strategy = GraphQL::Execution::Execute
293
- @default_mask = GraphQL::Schema::NullMask
294
- @rebuilding_artifacts = false
295
- @context_class = GraphQL::Query::Context
296
- @introspection_namespace = nil
297
- @introspection_system = nil
298
- @interpreter = false
299
- @error_bubbling = false
300
- @disable_introspection_entry_points = false
301
- @disable_schema_introspection_entry_point = false
302
- @disable_type_introspection_entry_point = false
303
- end
304
-
305
- # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
306
- def interpreter?
307
- query_execution_strategy == GraphQL::Execution::Interpreter &&
308
- mutation_execution_strategy == GraphQL::Execution::Interpreter &&
309
- subscription_execution_strategy == GraphQL::Execution::Interpreter
310
- end
311
-
312
- def inspect
313
- "#<#{self.class.name} ...>"
314
- end
315
-
316
- def initialize_copy(other)
317
- super
318
- @orphan_types = other.orphan_types.dup
319
- @directives = other.directives.dup
320
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
321
- @middleware = other.middleware.dup
322
- @query_analyzers = other.query_analyzers.dup
323
- @multiplex_analyzers = other.multiplex_analyzers.dup
324
- @tracers = other.tracers.dup
325
- @possible_types = GraphQL::Schema::PossibleTypes.new(self)
326
-
327
- @lazy_methods = other.lazy_methods.dup
328
-
329
- @instrumenters = Hash.new { |h, k| h[k] = [] }
330
- other.instrumenters.each do |key, insts|
331
- @instrumenters[key].concat(insts)
332
- end
333
-
334
- if other.rescues?
335
- @rescue_middleware = other.rescue_middleware
336
- end
337
158
 
338
- # This will be rebuilt when it's requested
339
- # or during a later `define` call
340
- @types = nil
341
- @introspection_system = nil
342
- end
343
-
344
- def rescue_from(*args, &block)
345
- rescue_middleware.rescue_from(*args, &block)
346
- end
347
-
348
- def remove_handler(*args, &block)
349
- rescue_middleware.remove_handler(*args, &block)
350
- end
351
-
352
- def using_ast_analysis?
353
- @analysis_engine == GraphQL::Analysis::AST
354
- end
355
-
356
- # For forwards-compatibility with Schema classes
357
- alias :graphql_definition :itself
358
-
359
- def deprecated_define(**kwargs, &block)
360
- super
361
- ensure_defined
362
- # Assert that all necessary configs are present:
363
- validation_error = Validation.validate(self)
364
- validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
365
- rebuild_artifacts
366
-
367
- @definition_error = nil
368
- nil
369
- rescue StandardError => err
370
- if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
371
- raise
372
- else
373
- # Raise this error _later_ to avoid messing with Rails constant loading
374
- @definition_error = err
375
- end
376
- nil
377
- end
378
-
379
- # Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
380
- # @param instrumentation_type [Symbol]
381
- # @param instrumenter
382
- # @return [void]
383
- def instrument(instrumentation_type, instrumenter)
384
- @instrumenters[instrumentation_type] << instrumenter
385
- if instrumentation_type == :field
386
- rebuild_artifacts
387
- end
388
- end
389
-
390
- # @return [Array<GraphQL::BaseType>] The root types of this schema
391
- def root_types
392
- @root_types ||= begin
393
- rebuild_artifacts
394
- @root_types
395
- end
396
- end
397
-
398
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
399
- # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
400
- def types
401
- @types ||= begin
402
- rebuild_artifacts
403
- @types
404
- end
405
- end
406
-
407
- def get_type(type_name)
408
- @types[type_name]
409
- end
410
-
411
- # @api private
412
- def introspection_system
413
- @introspection_system ||= begin
414
- rebuild_artifacts
415
- @introspection_system
416
- end
417
- end
418
-
419
- # Returns a list of Arguments and Fields referencing a certain type
420
- # @param type_name [String]
421
- # @return [Hash]
422
- def references_to(type_name = nil)
423
- rebuild_artifacts unless defined?(@type_reference_map)
424
- if type_name
425
- @type_reference_map.fetch(type_name, [])
426
- else
427
- @type_reference_map
428
- end
429
- end
430
-
431
- # Returns a list of Union types in which a type is a member
432
- # @param type [GraphQL::ObjectType]
433
- # @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
434
- def union_memberships(type)
435
- rebuild_artifacts unless defined?(@union_memberships)
436
- @union_memberships.fetch(type.name, [])
437
- end
438
-
439
- # Execute a query on itself. Raises an error if the schema definition is invalid.
440
- # @see {Query#initialize} for arguments.
441
- # @return [Hash] query result, ready to be serialized as JSON
442
- def execute(query_str = nil, **kwargs)
443
- if query_str
444
- kwargs[:query] = query_str
445
- end
446
- # Some of the query context _should_ be passed to the multiplex, too
447
- multiplex_context = if (ctx = kwargs[:context])
448
- {
449
- backtrace: ctx[:backtrace],
450
- tracers: ctx[:tracers],
451
- }
452
- else
453
- {}
454
- end
455
- # Since we're running one query, don't run a multiplex-level complexity analyzer
456
- all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
457
- all_results[0]
458
- end
459
-
460
- # Execute several queries on itself. Raises an error if the schema definition is invalid.
461
- # @example Run several queries at once
462
- # context = { ... }
463
- # queries = [
464
- # { query: params[:query_1], variables: params[:variables_1], context: context },
465
- # { query: params[:query_2], variables: params[:variables_2], context: context },
466
- # ]
467
- # results = MySchema.multiplex(queries)
468
- # render json: {
469
- # result_1: results[0],
470
- # result_2: results[1],
471
- # }
472
- #
473
- # @see {Query#initialize} for query keyword arguments
474
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
475
- # @param queries [Array<Hash>] Keyword arguments for each query
476
- # @param context [Hash] Multiplex-level context
477
- # @return [Array<Hash>] One result for each query in the input
478
- def multiplex(queries, **kwargs)
479
- with_definition_error_check {
480
- GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
481
- }
482
- end
483
-
484
- # Search for a schema member using a string path
485
- # @example Finding a Field
486
- # Schema.find("Ensemble.musicians")
487
- #
488
- # @see {GraphQL::Schema::Finder} for more examples
489
- # @param path [String] A dot-separated path to the member
490
- # @raise [Schema::Finder::MemberNotFoundError] if path could not be found
491
- # @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
492
- def find(path)
493
- rebuild_artifacts unless defined?(@finder)
494
- @find_cache[path] ||= @finder.find(path)
495
- end
496
-
497
- # Resolve field named `field_name` for type `parent_type`.
498
- # Handles dynamic fields `__typename`, `__type` and `__schema`, too
499
- # @param parent_type [String, GraphQL::BaseType]
500
- # @param field_name [String]
501
- # @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
502
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
503
- def get_field(parent_type, field_name)
504
- with_definition_error_check do
505
- parent_type_name = case parent_type
506
- when GraphQL::BaseType, Class, Module
507
- parent_type.graphql_name
508
- when String
509
- parent_type
510
- else
511
- raise "Unexpected parent_type: #{parent_type}"
159
+ def trace_class(new_class = nil)
160
+ if new_class
161
+ # If any modules were already added for `:default`,
162
+ # re-apply them here
163
+ mods = trace_modules_for(:default)
164
+ mods.each { |mod| new_class.include(mod) }
165
+ trace_mode(:default, new_class)
166
+ backtrace_class = Class.new(new_class)
167
+ backtrace_class.include(GraphQL::Backtrace::Trace)
168
+ trace_mode(:default_backtrace, backtrace_class)
512
169
  end
170
+ trace_class_for(:default, build: true)
171
+ end
513
172
 
514
- defined_field = @instrumented_field_map[parent_type_name][field_name]
515
- if defined_field
516
- defined_field
517
- elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
518
- entry_point_field
519
- elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
520
- dynamic_field
173
+ # @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
174
+ def trace_class_for(mode, build: false)
175
+ if (trace_class = own_trace_modes[mode])
176
+ trace_class
177
+ elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
178
+ trace_class
179
+ elsif build
180
+ own_trace_modes[mode] = build_trace_mode(mode)
521
181
  else
522
182
  nil
523
183
  end
524
184
  end
525
- end
526
-
527
- # Fields for this type, after instrumentation is applied
528
- # @return [Hash<String, GraphQL::Field>]
529
- def get_fields(type)
530
- @instrumented_field_map[type.graphql_name]
531
- end
532
185
 
533
- def type_from_ast(ast_node, context:)
534
- GraphQL::Schema::TypeExpression.build_type(self, ast_node)
535
- end
536
-
537
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
538
- # @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
539
- # @param context [GraphQL::Query::Context] The context for the current query
540
- # @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
541
- def possible_types(type_defn, context = GraphQL::Query::NullContext)
542
- if context == GraphQL::Query::NullContext
543
- @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
544
- @possible_types.possible_types(type_defn, context)
545
- else
546
- # Use the incoming context to cache this instance --
547
- # if it were cached on the schema, we'd have a memory leak
548
- # https://github.com/rmosolgo/graphql-ruby/issues/2878
549
- ns = context.namespace(:possible_types)
550
- per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
551
- per_query_possible_types.possible_types(type_defn, context)
552
- end
553
- end
554
-
555
- # @see [GraphQL::Schema::Warden] Resticted access to root types
556
- # @return [GraphQL::ObjectType, nil]
557
- def root_type_for_operation(operation)
558
- case operation
559
- when "query"
560
- query
561
- when "mutation"
562
- mutation
563
- when "subscription"
564
- subscription
565
- else
566
- raise ArgumentError, "unknown operation type: #{operation}"
567
- end
568
- end
569
-
570
- def execution_strategy_for_operation(operation)
571
- case operation
572
- when "query"
573
- query_execution_strategy
574
- when "mutation"
575
- mutation_execution_strategy
576
- when "subscription"
577
- subscription_execution_strategy
578
- else
579
- raise ArgumentError, "unknown operation type: #{operation}"
580
- end
581
- end
582
-
583
- # Determine the GraphQL type for a given object.
584
- # This is required for unions and interfaces (including Relay's `Node` interface)
585
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
586
- # @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
587
- # @param object [Any] An application object which GraphQL is currently resolving on
588
- # @param ctx [GraphQL::Query::Context] The context for the current query
589
- # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
590
- def resolve_type(type, object, ctx = :__undefined__)
591
- check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
592
- if @resolve_type_proc.nil?
593
- raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
594
- end
595
- @resolve_type_proc.call(ok_type, ok_object, ok_ctx)
596
- end
597
- end
598
-
599
- # This is a compatibility hack so that instance-level and class-level
600
- # methods can get correctness checks without calling one another
601
- # @api private
602
- def check_resolved_type(type, object, ctx = :__undefined__)
603
- if ctx == :__undefined__
604
- # Old method signature
605
- ctx = object
606
- object = type
607
- type = nil
186
+ # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
187
+ # {default_trace_mode} is used when no `trace_mode: ...` is requested.
188
+ #
189
+ # When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
190
+ # unless `trace_mode` is explicitly given. (This class will not recieve any default trace modules.)
191
+ #
192
+ # Subclasses of the schema will use `trace_class` as a base class for this mode and those
193
+ # subclass also will _not_ receive default tracing modules.
194
+ #
195
+ # @param mode_name [Symbol]
196
+ # @param trace_class [Class] subclass of GraphQL::Tracing::Trace
197
+ # @return void
198
+ def trace_mode(mode_name, trace_class)
199
+ own_trace_modes[mode_name] = trace_class
200
+ nil
608
201
  end
609
202
 
610
- if object.is_a?(GraphQL::Schema::Object)
611
- object = object.object
203
+ def own_trace_modes
204
+ @own_trace_modes ||= {}
612
205
  end
613
206
 
614
- if type.respond_to?(:graphql_definition)
615
- type = type.graphql_definition
207
+ module DefaultTraceClass
616
208
  end
617
209
 
618
- # Prefer a type-local function; fall back to the schema-level function
619
- type_proc = type && type.resolve_type_proc
620
- type_result = if type_proc
621
- type_proc.call(object, ctx)
622
- else
623
- yield(type, object, ctx)
624
- end
210
+ private_constant :DefaultTraceClass
625
211
 
626
- if type_result.nil?
627
- nil
628
- else
629
- after_lazy(type_result) do |resolved_type_result|
630
- if resolved_type_result.respond_to?(:graphql_definition)
631
- resolved_type_result = resolved_type_result.graphql_definition
212
+ def build_trace_mode(mode)
213
+ case mode
214
+ when :default
215
+ # Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
216
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || GraphQL::Tracing::Trace
217
+ Class.new(base_class) do
218
+ include DefaultTraceClass
632
219
  end
633
- if !resolved_type_result.is_a?(GraphQL::BaseType)
634
- type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
635
- raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
636
- else
637
- resolved_type_result
220
+ when :default_backtrace
221
+ schema_base_class = trace_class_for(:default, build: true)
222
+ Class.new(schema_base_class) do
223
+ include(GraphQL::Backtrace::Trace)
638
224
  end
639
- end
640
- end
641
- end
642
-
643
- def resolve_type=(new_resolve_type_proc)
644
- callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
645
- @resolve_type_proc = callable
646
- end
647
-
648
- # Fetch an application object by its unique id
649
- # @param id [String] A unique identifier, provided previously by this GraphQL schema
650
- # @param ctx [GraphQL::Query::Context] The context for the current query
651
- # @return [Any] The application object identified by `id`
652
- def object_from_id(id, ctx)
653
- if @object_from_id_proc.nil?
654
- raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
655
- else
656
- @object_from_id_proc.call(id, ctx)
657
- end
658
- end
659
-
660
- # @param new_proc [#call] A new callable for fetching objects by ID
661
- def object_from_id=(new_proc)
662
- @object_from_id_proc = new_proc
663
- end
664
-
665
- # When we encounter a type error during query execution, we call this hook.
666
- #
667
- # You can use this hook to write a log entry,
668
- # add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
669
- # or raise an exception and halt query execution.
670
- #
671
- # @example A `nil` is encountered by a non-null field
672
- # type_error ->(err, query_ctx) {
673
- # err.is_a?(GraphQL::InvalidNullError) # => true
674
- # }
675
- #
676
- # @example An object doesn't resolve to one of a {UnionType}'s members
677
- # type_error ->(err, query_ctx) {
678
- # err.is_a?(GraphQL::UnresolvedTypeError) # => true
679
- # }
680
- #
681
- # @see {DefaultTypeError} is the default behavior.
682
- # @param err [GraphQL::TypeError] The error encountered during execution
683
- # @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
684
- # @return void
685
- def type_error(err, ctx)
686
- @type_error_proc.call(err, ctx)
687
- end
688
-
689
- # @param new_proc [#call] A new callable for handling type errors during execution
690
- def type_error=(new_proc)
691
- @type_error_proc = new_proc
692
- end
693
-
694
- # Can't delegate to `class`
695
- alias :_schema_class :class
696
- def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
697
- def_delegators :_schema_class, :directive
698
- def_delegators :_schema_class, :error_handler
699
- def_delegators :_schema_class, :validate
700
-
701
-
702
- # Given this schema member, find the class-based definition object
703
- # whose `method_name` should be treated as an application hook
704
- # @see {.visible?}
705
- # @see {.accessible?}
706
- def call_on_type_class(member, method_name, context, default:)
707
- member = if member.respond_to?(:type_class)
708
- member.type_class
709
- else
710
- member
711
- end
225
+ else
226
+ # First, see if the superclass has a custom-defined class for this.
227
+ # Then, if it doesn't, use this class's default trace
228
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
229
+ # Prepare the default trace class if it hasn't been initialized yet
230
+ base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
231
+ mods = trace_modules_for(mode)
232
+ if base_class < DefaultTraceClass
233
+ mods = trace_modules_for(:default) + mods
234
+ end
235
+ # Copy the existing default options into this mode's options
236
+ default_options = trace_options_for(:default)
237
+ add_trace_options_for(mode, default_options)
712
238
 
713
- if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
714
- member = t
239
+ Class.new(base_class) do
240
+ mods.any? && include(*mods)
241
+ end
242
+ end
715
243
  end
716
244
 
717
- if member.respond_to?(method_name)
718
- member.public_send(method_name, context)
719
- else
720
- default
245
+ def own_trace_modules
246
+ @own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
721
247
  end
722
- end
723
248
 
724
- def visible?(member, context)
725
- call_on_type_class(member, :visible?, context, default: true)
726
- end
727
-
728
- def accessible?(member, context)
729
- call_on_type_class(member, :accessible?, context, default: true)
730
- end
731
-
732
- # A function to call when {#execute} receives an invalid query string
733
- #
734
- # @see {DefaultParseError} is the default behavior.
735
- # @param err [GraphQL::ParseError] The error encountered during parsing
736
- # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
737
- # @return void
738
- def parse_error(err, ctx)
739
- @parse_error_proc.call(err, ctx)
740
- end
741
-
742
- # @param new_proc [#call] A new callable for handling parse errors during execution
743
- def parse_error=(new_proc)
744
- @parse_error_proc = new_proc
745
- end
746
-
747
- # Get a unique identifier from this object
748
- # @param object [Any] An application object
749
- # @param type [GraphQL::BaseType] The current type definition
750
- # @param ctx [GraphQL::Query::Context] the context for the current query
751
- # @return [String] a unique identifier for `object` which clients can use to refetch it
752
- def id_from_object(object, type, ctx)
753
- if @id_from_object_proc.nil?
754
- raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
755
- else
756
- @id_from_object_proc.call(object, type, ctx)
757
- end
758
- end
759
-
760
- # @param new_proc [#call] A new callable for generating unique IDs
761
- def id_from_object=(new_proc)
762
- @id_from_object_proc = new_proc
763
- end
764
-
765
- # Create schema with the result of an introspection query.
766
- # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
767
- # @return [GraphQL::Schema] the schema described by `input`
768
- def self.from_introspection(introspection_result)
769
- GraphQL::Schema::Loader.load(introspection_result)
770
- end
771
-
772
- # Create schema from an IDL schema or file containing an IDL definition.
773
- # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
774
- # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
775
- # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
776
- # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
777
- # @return [Class] the schema described by `document`
778
- def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
779
- # If the file ends in `.graphql`, treat it like a filepath
780
- if definition_or_path.end_with?(".graphql")
781
- GraphQL::Schema::BuildFromDefinition.from_definition_path(
782
- definition_or_path,
783
- default_resolve: default_resolve,
784
- parser: parser,
785
- using: using,
786
- )
787
- else
788
- GraphQL::Schema::BuildFromDefinition.from_definition(
789
- definition_or_path,
790
- default_resolve: default_resolve,
791
- parser: parser,
792
- using: using,
793
- )
249
+ # @return [Array<Module>] Modules added for tracing in `trace_mode`, including inherited ones
250
+ def trace_modules_for(trace_mode)
251
+ modules = own_trace_modules[trace_mode]
252
+ if superclass.respond_to?(:trace_modules_for)
253
+ modules += superclass.trace_modules_for(trace_mode)
254
+ end
255
+ modules
794
256
  end
795
- end
796
-
797
- # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
798
- class InvalidDocumentError < Error; end;
799
-
800
- # Return the GraphQL IDL for the schema
801
- # @param context [Hash]
802
- # @param only [<#call(member, ctx)>]
803
- # @param except [<#call(member, ctx)>]
804
- # @return [String]
805
- def to_definition(only: nil, except: nil, context: {})
806
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
807
- end
808
-
809
- # Return the GraphQL::Language::Document IDL AST for the schema
810
- # @param context [Hash]
811
- # @param only [<#call(member, ctx)>]
812
- # @param except [<#call(member, ctx)>]
813
- # @return [GraphQL::Language::Document]
814
- def to_document(only: nil, except: nil, context: {})
815
- GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
816
- end
817
-
818
- # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
819
- # @param context [Hash]
820
- # @param only [<#call(member, ctx)>]
821
- # @param except [<#call(member, ctx)>]
822
- # @return [Hash] GraphQL result
823
- def as_json(only: nil, except: nil, context: {})
824
- execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
825
- end
826
-
827
- # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
828
- # @see {#as_json}
829
- # @return [String]
830
- def to_json(*args)
831
- JSON.pretty_generate(as_json(*args))
832
- end
833
-
834
- def new_connections?
835
- !!connections
836
- end
837
-
838
- attr_accessor :connections
839
257
 
840
- class << self
841
- extend Forwardable
842
- # For compatibility, these methods all:
843
- # - Cause the Schema instance to be created, if it hasn't been created yet
844
- # - Delegate to that instance
845
- # Eventually, the methods will be moved into this class, removing the need for the singleton.
846
- def_delegators :graphql_definition,
847
- # Execution
848
- :execution_strategy_for_operation,
849
- # Configuration
850
- :metadata, :redefine,
851
- :id_from_object_proc, :object_from_id_proc,
852
- :id_from_object=, :object_from_id=,
853
- :remove_handler
854
-
855
- # @return [GraphQL::Subscriptions]
856
- attr_accessor :subscriptions
857
258
 
858
259
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
859
260
  # @see {#as_json}
@@ -866,18 +267,29 @@ module GraphQL
866
267
  # @param context [Hash]
867
268
  # @param only [<#call(member, ctx)>]
868
269
  # @param except [<#call(member, ctx)>]
270
+ # @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
271
+ # @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
272
+ # @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
273
+ # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
274
+ # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
869
275
  # @return [Hash] GraphQL result
870
- def as_json(only: nil, except: nil, context: {})
871
- execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
276
+ def as_json(context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
277
+ introspection_query = Introspection.query(
278
+ include_deprecated_args: include_deprecated_args,
279
+ include_schema_description: include_schema_description,
280
+ include_is_repeatable: include_is_repeatable,
281
+ include_is_one_of: include_is_one_of,
282
+ include_specified_by_url: include_specified_by_url,
283
+ )
284
+
285
+ execute(introspection_query, context: context).to_h
872
286
  end
873
287
 
874
288
  # Return the GraphQL IDL for the schema
875
289
  # @param context [Hash]
876
- # @param only [<#call(member, ctx)>]
877
- # @param except [<#call(member, ctx)>]
878
290
  # @return [String]
879
- def to_definition(only: nil, except: nil, context: {})
880
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
291
+ def to_definition(context: {})
292
+ GraphQL::Schema::Printer.print_schema(self, context: context)
881
293
  end
882
294
 
883
295
  # Return the GraphQL::Language::Document IDL AST for the schema
@@ -886,6 +298,17 @@ module GraphQL
886
298
  GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
887
299
  end
888
300
 
301
+ # @return [String, nil]
302
+ def description(new_description = nil)
303
+ if new_description
304
+ @description = new_description
305
+ elsif defined?(@description)
306
+ @description
307
+ else
308
+ find_inherited_value(:description, nil)
309
+ end
310
+ end
311
+
889
312
  def find(path)
890
313
  if !@finder
891
314
  @find_cache = {}
@@ -894,22 +317,6 @@ module GraphQL
894
317
  @find_cache[path] ||= @finder.find(path)
895
318
  end
896
319
 
897
- def graphql_definition
898
- @graphql_definition ||= to_graphql
899
- end
900
-
901
- def default_filter
902
- GraphQL::Filter.new(except: default_mask)
903
- end
904
-
905
- def default_mask(new_mask = nil)
906
- if new_mask
907
- @own_default_mask = new_mask
908
- else
909
- @own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
910
- end
911
- end
912
-
913
320
  def static_validator
914
321
  GraphQL::StaticValidation::Validator.new(schema: self)
915
322
  end
@@ -927,84 +334,70 @@ module GraphQL
927
334
  find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
928
335
  end
929
336
 
930
- def to_graphql
931
- schema_defn = self.new
932
- schema_defn.raise_definition_error = true
933
- schema_defn.query = query && query.graphql_definition
934
- schema_defn.mutation = mutation && mutation.graphql_definition
935
- schema_defn.subscription = subscription && subscription.graphql_definition
936
- schema_defn.validate_timeout = validate_timeout
937
- schema_defn.max_complexity = max_complexity
938
- schema_defn.error_bubbling = error_bubbling
939
- schema_defn.max_depth = max_depth
940
- schema_defn.default_max_page_size = default_max_page_size
941
- schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
942
- schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
943
- schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
944
- schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
945
-
946
- prepped_dirs = {}
947
- directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
948
- schema_defn.directives = prepped_dirs
949
- schema_defn.introspection_namespace = introspection
950
- schema_defn.resolve_type = method(:resolve_type)
951
- schema_defn.object_from_id = method(:object_from_id)
952
- schema_defn.id_from_object = method(:id_from_object)
953
- schema_defn.type_error = method(:type_error)
954
- schema_defn.context_class = context_class
955
- schema_defn.cursor_encoder = cursor_encoder
956
- schema_defn.tracers.concat(tracers)
957
- schema_defn.query_analyzers.concat(query_analyzers)
958
- schema_defn.analysis_engine = analysis_engine
959
-
960
- schema_defn.middleware.concat(all_middleware)
961
- schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
962
- schema_defn.query_execution_strategy = query_execution_strategy
963
- schema_defn.mutation_execution_strategy = mutation_execution_strategy
964
- schema_defn.subscription_execution_strategy = subscription_execution_strategy
965
- schema_defn.default_mask = default_mask
966
- instrumenters.each do |step, insts|
967
- insts.each do |inst|
968
- schema_defn.instrumenters[step] << inst
969
- end
970
- end
971
-
972
- lazy_methods.each do |lazy_class, value_method|
973
- schema_defn.lazy_methods.set(lazy_class, value_method)
974
- end
975
-
976
- error_handler.each_rescue do |err_class, handler|
977
- schema_defn.rescue_from(err_class, &handler)
978
- end
979
-
980
- schema_defn.subscriptions ||= self.subscriptions
981
-
982
- if !schema_defn.interpreter?
983
- schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
984
- end
985
-
986
- if new_connections?
987
- schema_defn.connections = self.connections
988
- end
989
-
990
- schema_defn.send(:rebuild_artifacts)
991
-
992
- schema_defn
993
- end
994
-
995
337
  # Build a map of `{ name => type }` and return it
996
338
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
997
339
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
998
- def types
999
- non_introspection_types.merge(introspection_system.types)
340
+ def types(context = GraphQL::Query::NullContext.instance)
341
+ all_types = non_introspection_types.merge(introspection_system.types)
342
+ visible_types = {}
343
+ all_types.each do |k, v|
344
+ visible_types[k] =if v.is_a?(Array)
345
+ visible_t = nil
346
+ v.each do |t|
347
+ if t.visible?(context)
348
+ if visible_t.nil?
349
+ visible_t = t
350
+ else
351
+ raise DuplicateNamesError.new(
352
+ duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
353
+ )
354
+ end
355
+ end
356
+ end
357
+ visible_t
358
+ else
359
+ v
360
+ end
361
+ end
362
+ visible_types
1000
363
  end
1001
364
 
1002
365
  # @param type_name [String]
1003
366
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
1004
- def get_type(type_name)
1005
- own_types[type_name] ||
1006
- introspection_system.types[type_name] ||
1007
- find_inherited_value(:types, EMPTY_HASH)[type_name]
367
+ def get_type(type_name, context = GraphQL::Query::NullContext.instance)
368
+ local_entry = own_types[type_name]
369
+ type_defn = case local_entry
370
+ when nil
371
+ nil
372
+ when Array
373
+ visible_t = nil
374
+ warden = Warden.from_context(context)
375
+ local_entry.each do |t|
376
+ if warden.visible_type?(t, context)
377
+ if visible_t.nil?
378
+ visible_t = t
379
+ else
380
+ raise DuplicateNamesError.new(
381
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
382
+ )
383
+ end
384
+ end
385
+ end
386
+ visible_t
387
+ when Module
388
+ local_entry
389
+ else
390
+ raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
391
+ end
392
+
393
+ type_defn ||
394
+ introspection_system.types[type_name] || # todo context-specific introspection?
395
+ (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
396
+ end
397
+
398
+ # @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
399
+ def has_defined_type?(type_name)
400
+ own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
1008
401
  end
1009
402
 
1010
403
  # @api private
@@ -1073,7 +466,7 @@ module GraphQL
1073
466
  end
1074
467
  end
1075
468
 
1076
- # @see [GraphQL::Schema::Warden] Resticted access to root types
469
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
1077
470
  # @return [GraphQL::ObjectType, nil]
1078
471
  def root_type_for_operation(operation)
1079
472
  case operation
@@ -1092,10 +485,22 @@ module GraphQL
1092
485
  @root_types
1093
486
  end
1094
487
 
488
+ def warden_class
489
+ if defined?(@warden_class)
490
+ @warden_class
491
+ elsif superclass.respond_to?(:warden_class)
492
+ superclass.warden_class
493
+ else
494
+ GraphQL::Schema::Warden
495
+ end
496
+ end
497
+
498
+ attr_writer :warden_class
499
+
1095
500
  # @param type [Module] The type definition whose possible types you want to see
1096
501
  # @return [Hash<String, Module>] All possible types, if no `type` is given.
1097
502
  # @return [Array<Module>] Possible types for `type`, if it's given.
1098
- def possible_types(type = nil, context = GraphQL::Query::NullContext)
503
+ def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
1099
504
  if type
1100
505
  # TODO duck-typing `.possible_types` would probably be nicer here
1101
506
  if type.kind.union?
@@ -1104,9 +509,7 @@ module GraphQL
1104
509
  stored_possible_types = own_possible_types[type.graphql_name]
1105
510
  visible_possible_types = if stored_possible_types && type.kind.interface?
1106
511
  stored_possible_types.select do |possible_type|
1107
- # Use `.graphql_name` comparison to match legacy vs class-based types.
1108
- # When we don't need to support legacy `.define` types, use `.include?(type)` instead.
1109
- possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
512
+ possible_type.interfaces(context).include?(type)
1110
513
  end
1111
514
  else
1112
515
  stored_possible_types
@@ -1150,18 +553,17 @@ module GraphQL
1150
553
  attr_writer :dataloader_class
1151
554
 
1152
555
  def references_to(to_type = nil, from: nil)
1153
- @own_references_to ||= Hash.new { |h, k| h[k] = [] }
556
+ @own_references_to ||= {}
1154
557
  if to_type
1155
558
  if !to_type.is_a?(String)
1156
559
  to_type = to_type.graphql_name
1157
560
  end
1158
561
 
1159
562
  if from
1160
- @own_references_to[to_type] << from
563
+ refs = @own_references_to[to_type] ||= []
564
+ refs << from
1161
565
  else
1162
- own_refs = @own_references_to[to_type]
1163
- inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
1164
- own_refs + inherited_refs
566
+ get_references_to(to_type) || EMPTY_ARRAY
1165
567
  end
1166
568
  else
1167
569
  # `@own_references_to` can be quite large for big schemas,
@@ -1181,19 +583,19 @@ module GraphQL
1181
583
  GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
1182
584
  end
1183
585
 
1184
- def get_field(type_or_name, field_name)
586
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
1185
587
  parent_type = case type_or_name
1186
588
  when LateBoundType
1187
- get_type(type_or_name.name)
589
+ get_type(type_or_name.name, context)
1188
590
  when String
1189
- get_type(type_or_name)
591
+ get_type(type_or_name, context)
1190
592
  when Module
1191
593
  type_or_name
1192
594
  else
1193
- raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
595
+ raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
1194
596
  end
1195
597
 
1196
- if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
598
+ if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
1197
599
  field
1198
600
  elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
1199
601
  entry_point_field
@@ -1204,8 +606,8 @@ module GraphQL
1204
606
  end
1205
607
  end
1206
608
 
1207
- def get_fields(type)
1208
- type.fields
609
+ def get_fields(type, context = GraphQL::Query::NullContext.instance)
610
+ type.fields(context)
1209
611
  end
1210
612
 
1211
613
  def introspection(new_introspection_namespace = nil)
@@ -1241,27 +643,47 @@ module GraphQL
1241
643
  end
1242
644
  end
1243
645
 
1244
- def query_execution_strategy(new_query_execution_strategy = nil)
646
+ def default_page_size(new_default_page_size = nil)
647
+ if new_default_page_size
648
+ @default_page_size = new_default_page_size
649
+ else
650
+ @default_page_size || find_inherited_value(:default_page_size)
651
+ end
652
+ end
653
+
654
+ def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
655
+ if deprecation_warning
656
+ warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
657
+ warn " #{caller(1, 1).first}"
658
+ end
1245
659
  if new_query_execution_strategy
1246
660
  @query_execution_strategy = new_query_execution_strategy
1247
661
  else
1248
- @query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
662
+ @query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
1249
663
  end
1250
664
  end
1251
665
 
1252
- def mutation_execution_strategy(new_mutation_execution_strategy = nil)
666
+ def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
667
+ if deprecation_warning
668
+ warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
669
+ warn " #{caller(1, 1).first}"
670
+ end
1253
671
  if new_mutation_execution_strategy
1254
672
  @mutation_execution_strategy = new_mutation_execution_strategy
1255
673
  else
1256
- @mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
674
+ @mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
1257
675
  end
1258
676
  end
1259
677
 
1260
- def subscription_execution_strategy(new_subscription_execution_strategy = nil)
678
+ def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
679
+ if deprecation_warning
680
+ warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
681
+ warn " #{caller(1, 1).first}"
682
+ end
1261
683
  if new_subscription_execution_strategy
1262
684
  @subscription_execution_strategy = new_subscription_execution_strategy
1263
685
  else
1264
- @subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
686
+ @subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
1265
687
  end
1266
688
  end
1267
689
 
@@ -1286,14 +708,34 @@ module GraphQL
1286
708
  else
1287
709
  string_or_document
1288
710
  end
1289
- query = GraphQL::Query.new(self, document: doc, context: context)
711
+ query = query_class.new(self, document: doc, context: context)
1290
712
  validator_opts = { schema: self }
1291
713
  rules && (validator_opts[:rules] = rules)
1292
714
  validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1293
- res = validator.validate(query, timeout: validate_timeout)
715
+ res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
1294
716
  res[:errors]
1295
717
  end
1296
718
 
719
+ def query_class(new_query_class = NOT_CONFIGURED)
720
+ if NOT_CONFIGURED.equal?(new_query_class)
721
+ @query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
722
+ else
723
+ @query_class = new_query_class
724
+ end
725
+ end
726
+
727
+ attr_writer :validate_max_errors
728
+
729
+ def validate_max_errors(new_validate_max_errors = nil)
730
+ if new_validate_max_errors
731
+ @validate_max_errors = new_validate_max_errors
732
+ elsif defined?(@validate_max_errors)
733
+ @validate_max_errors
734
+ else
735
+ find_inherited_value(:validate_max_errors)
736
+ end
737
+ end
738
+
1297
739
  attr_writer :max_complexity
1298
740
 
1299
741
  def max_complexity(max_complexity = nil)
@@ -1313,19 +755,18 @@ module GraphQL
1313
755
  end
1314
756
 
1315
757
  def using_ast_analysis?
1316
- analysis_engine == GraphQL::Analysis::AST
758
+ true
1317
759
  end
1318
760
 
1319
761
  def interpreter?
1320
- query_execution_strategy == GraphQL::Execution::Interpreter &&
1321
- mutation_execution_strategy == GraphQL::Execution::Interpreter &&
1322
- subscription_execution_strategy == GraphQL::Execution::Interpreter
762
+ true
1323
763
  end
1324
764
 
1325
765
  attr_writer :interpreter
1326
766
 
1327
767
  def error_bubbling(new_error_bubbling = nil)
1328
768
  if !new_error_bubbling.nil?
769
+ warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
1329
770
  @error_bubbling = new_error_bubbling
1330
771
  else
1331
772
  @error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
@@ -1336,9 +777,10 @@ module GraphQL
1336
777
 
1337
778
  attr_writer :max_depth
1338
779
 
1339
- def max_depth(new_max_depth = nil)
780
+ def max_depth(new_max_depth = nil, count_introspection_fields: true)
1340
781
  if new_max_depth
1341
782
  @max_depth = new_max_depth
783
+ @count_introspection_fields = count_introspection_fields
1342
784
  elsif defined?(@max_depth)
1343
785
  @max_depth
1344
786
  else
@@ -1346,6 +788,14 @@ module GraphQL
1346
788
  end
1347
789
  end
1348
790
 
791
+ def count_introspection_fields
792
+ if defined?(@count_introspection_fields)
793
+ @count_introspection_fields
794
+ else
795
+ find_inherited_value(:count_introspection_fields, true)
796
+ end
797
+ end
798
+
1349
799
  def disable_introspection_entry_points
1350
800
  @disable_introspection_entry_points = true
1351
801
  # TODO: this clears the cache made in `def types`. But this is not a great solution.
@@ -1388,15 +838,43 @@ module GraphQL
1388
838
  end
1389
839
  end
1390
840
 
841
+ # @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
842
+ # @return [Array<Module>] Type definitions added to this schema
843
+ def extra_types(*new_extra_types)
844
+ if new_extra_types.any?
845
+ new_extra_types = new_extra_types.flatten
846
+ @own_extra_types ||= []
847
+ @own_extra_types.concat(new_extra_types)
848
+ end
849
+ inherited_et = find_inherited_value(:extra_types, nil)
850
+ if inherited_et
851
+ if @own_extra_types
852
+ inherited_et + @own_extra_types
853
+ else
854
+ inherited_et
855
+ end
856
+ else
857
+ @own_extra_types || EMPTY_ARRAY
858
+ end
859
+ end
860
+
1391
861
  def orphan_types(*new_orphan_types)
1392
862
  if new_orphan_types.any?
1393
863
  new_orphan_types = new_orphan_types.flatten
1394
864
  add_type_and_traverse(new_orphan_types, root: false)
1395
- @orphan_types = new_orphan_types
1396
865
  own_orphan_types.concat(new_orphan_types.flatten)
1397
866
  end
1398
867
 
1399
- find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
868
+ inherited_ot = find_inherited_value(:orphan_types, nil)
869
+ if inherited_ot
870
+ if own_orphan_types.any?
871
+ inherited_ot + own_orphan_types
872
+ else
873
+ inherited_ot
874
+ end
875
+ else
876
+ own_orphan_types
877
+ end
1400
878
  end
1401
879
 
1402
880
  def default_execution_strategy
@@ -1415,6 +893,26 @@ module GraphQL
1415
893
  end
1416
894
  end
1417
895
 
896
+ def default_logger(new_default_logger = NOT_CONFIGURED)
897
+ if NOT_CONFIGURED.equal?(new_default_logger)
898
+ if defined?(@default_logger)
899
+ @default_logger
900
+ elsif superclass.respond_to?(:default_logger)
901
+ superclass.default_logger
902
+ elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
903
+ rails_logger
904
+ else
905
+ def_logger = Logger.new($stdout)
906
+ def_logger.info! # It doesn't output debug info by default
907
+ def_logger
908
+ end
909
+ elsif new_default_logger == nil
910
+ @default_logger = Logger.new(IO::NULL)
911
+ else
912
+ @default_logger = new_default_logger
913
+ end
914
+ end
915
+
1418
916
  def context_class(new_context_class = nil)
1419
917
  if new_context_class
1420
918
  @context_class = new_context_class
@@ -1425,26 +923,63 @@ module GraphQL
1425
923
 
1426
924
  def rescue_from(*err_classes, &handler_block)
1427
925
  err_classes.each do |err_class|
1428
- error_handler.rescue_from(err_class, handler_block)
926
+ Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
927
+ end
928
+ end
929
+
930
+ NEW_HANDLER_HASH = ->(h, k) {
931
+ h[k] = {
932
+ class: k,
933
+ handler: nil,
934
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
935
+ }
936
+ }
937
+
938
+ def error_handlers
939
+ @error_handlers ||= {
940
+ class: nil,
941
+ handler: nil,
942
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
943
+ }
944
+ end
945
+
946
+ # @api private
947
+ def handle_or_reraise(context, err)
948
+ handler = Execution::Errors.find_handler_for(self, err.class)
949
+ if handler
950
+ obj = context[:current_object]
951
+ args = context[:current_arguments]
952
+ args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
953
+ field = context[:current_field]
954
+ if obj.is_a?(GraphQL::Schema::Object)
955
+ obj = obj.object
956
+ end
957
+ handler[:handler].call(err, obj, args, context, field)
958
+ else
959
+ raise err
1429
960
  end
1430
961
  end
1431
962
 
1432
963
  # rubocop:disable Lint/DuplicateMethods
1433
964
  module ResolveTypeWithType
1434
965
  def resolve_type(type, obj, ctx)
1435
- first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
966
+ maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1436
967
  type.resolve_type(obj, ctx)
1437
968
  else
1438
969
  super
1439
970
  end
1440
971
 
1441
- after_lazy(first_resolved_type) do |resolved_type|
1442
- if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
1443
- if resolved_value
1444
- [resolved_type, resolved_value]
1445
- else
1446
- resolved_type
1447
- end
972
+ after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
973
+ if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
974
+ resolved_type = resolve_type_result[0]
975
+ resolved_value = resolve_type_result[1]
976
+ else
977
+ resolved_type = resolve_type_result
978
+ resolved_value = obj
979
+ end
980
+
981
+ if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
982
+ [resolved_type, resolved_value]
1448
983
  else
1449
984
  raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
1450
985
  end
@@ -1453,17 +988,19 @@ module GraphQL
1453
988
  end
1454
989
 
1455
990
  def resolve_type(type, obj, ctx)
1456
- if type.kind.object?
1457
- type
1458
- else
1459
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
1460
- end
991
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{type.name})"
1461
992
  end
1462
993
  # rubocop:enable Lint/DuplicateMethods
1463
994
 
1464
995
  def inherited(child_class)
1465
996
  if self == GraphQL::Schema
1466
997
  child_class.directives(default_directives.values)
998
+ child_class.extend(SubclassGetReferencesTo)
999
+ end
1000
+ # Make sure the child class has these built out, so that
1001
+ # subclasses can be modified by later calls to `trace_with`
1002
+ own_trace_modes.each do |name, _class|
1003
+ child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
1467
1004
  end
1468
1005
  child_class.singleton_class.prepend(ResolveTypeWithType)
1469
1006
  super
@@ -1478,23 +1015,16 @@ module GraphQL
1478
1015
  end
1479
1016
 
1480
1017
  def visible?(member, ctx)
1481
- member.type_class.visible?(ctx)
1018
+ member.visible?(ctx)
1482
1019
  end
1483
1020
 
1484
- def accessible?(member, ctx)
1485
- member.type_class.accessible?(ctx)
1021
+ def schema_directive(dir_class, **options)
1022
+ @own_schema_directives ||= []
1023
+ Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
1486
1024
  end
1487
1025
 
1488
- # This hook is called when a client tries to access one or more
1489
- # fields that fail the `accessible?` check.
1490
- #
1491
- # By default, an error is added to the response. Override this hook to
1492
- # track metrics or return a different error to the client.
1493
- #
1494
- # @param error [InaccessibleFieldsError] The analysis error for this check
1495
- # @return [AnalysisError, nil] Return an error to skip the query
1496
- def inaccessible_fields(error)
1497
- error
1026
+ def schema_directives
1027
+ Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
1498
1028
  end
1499
1029
 
1500
1030
  # This hook is called when an object fails an `authorized?` check.
@@ -1532,41 +1062,39 @@ module GraphQL
1532
1062
  unauthorized_object(unauthorized_error)
1533
1063
  end
1534
1064
 
1535
- def type_error(type_err, ctx)
1536
- DefaultTypeError.call(type_err, ctx)
1065
+ def type_error(type_error, ctx)
1066
+ case type_error
1067
+ when GraphQL::InvalidNullError
1068
+ ctx.errors << type_error
1069
+ when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
1070
+ raise type_error
1071
+ when GraphQL::IntegerDecodingError
1072
+ nil
1073
+ end
1537
1074
  end
1538
1075
 
1539
1076
  # A function to call when {#execute} receives an invalid query string
1540
1077
  #
1541
1078
  # The default is to add the error to `context.errors`
1542
- # @param err [GraphQL::ParseError] The error encountered during parsing
1079
+ # @param parse_err [GraphQL::ParseError] The error encountered during parsing
1543
1080
  # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
1544
1081
  # @return void
1545
1082
  def parse_error(parse_err, ctx)
1546
1083
  ctx.errors.push(parse_err)
1547
1084
  end
1548
1085
 
1549
- # @return [GraphQL::Execution::Errors]
1550
- def error_handler
1551
- @error_handler ||= GraphQL::Execution::Errors.new(self)
1552
- end
1553
-
1554
1086
  def lazy_resolve(lazy_class, value_method)
1555
1087
  lazy_methods.set(lazy_class, value_method)
1556
1088
  end
1557
1089
 
1558
1090
  def instrument(instrument_step, instrumenter, options = {})
1559
- if instrument_step == :field
1560
- GraphQL::Deprecation.warn "Field instrumentation (#{instrumenter.inspect}) will be removed in GraphQL-Ruby 2.0, please upgrade to field extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1561
- end
1562
-
1563
- step = if instrument_step == :field && options[:after_built_ins]
1564
- :field_after_built_ins
1565
- else
1566
- instrument_step
1567
- end
1091
+ warn <<~WARN
1092
+ Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
1093
+ (From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
1568
1094
 
1569
- own_instrumenters[step] << instrumenter
1095
+ WARN
1096
+ trace_with(Tracing::LegacyHooksTrace)
1097
+ own_instrumenters[instrument_step] << instrumenter
1570
1098
  end
1571
1099
 
1572
1100
  # Add several directives at once
@@ -1576,7 +1104,12 @@ module GraphQL
1576
1104
  new_directives.flatten.each { |d| directive(d) }
1577
1105
  end
1578
1106
 
1579
- find_inherited_value(:directives, default_directives).merge(own_directives)
1107
+ inherited_dirs = find_inherited_value(:directives, default_directives)
1108
+ if own_directives.any?
1109
+ inherited_dirs.merge(own_directives)
1110
+ else
1111
+ inherited_dirs
1112
+ end
1580
1113
  end
1581
1114
 
1582
1115
  # Attach a single directive to this schema
@@ -1591,10 +1124,17 @@ module GraphQL
1591
1124
  "include" => GraphQL::Schema::Directive::Include,
1592
1125
  "skip" => GraphQL::Schema::Directive::Skip,
1593
1126
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
1127
+ "oneOf" => GraphQL::Schema::Directive::OneOf,
1128
+ "specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
1594
1129
  }.freeze
1595
1130
  end
1596
1131
 
1597
1132
  def tracer(new_tracer)
1133
+ default_trace = trace_class_for(:default, build: true)
1134
+ if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
1135
+ trace_with(GraphQL::Tracing::CallLegacyTracers)
1136
+ end
1137
+
1598
1138
  own_tracers << new_tracer
1599
1139
  end
1600
1140
 
@@ -1602,25 +1142,96 @@ module GraphQL
1602
1142
  find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1603
1143
  end
1604
1144
 
1605
- def query_analyzer(new_analyzer)
1606
- if new_analyzer == GraphQL::Authorization::Analyzer
1607
- GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1145
+ # Mix `trace_mod` into this schema's `Trace` class so that its methods
1146
+ # will be called at runtime.
1147
+ #
1148
+ # @param trace_mod [Module] A module that implements tracing methods
1149
+ # @param mode [Symbol] Trace module will only be used for this trade mode
1150
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1151
+ # @return [void]
1152
+ def trace_with(trace_mod, mode: :default, **options)
1153
+ if mode.is_a?(Array)
1154
+ mode.each { |m| trace_with(trace_mod, mode: m, **options) }
1155
+ else
1156
+ tc = own_trace_modes[mode] ||= build_trace_mode(mode)
1157
+ tc.include(trace_mod)
1158
+ own_trace_modules[mode] << trace_mod
1159
+ add_trace_options_for(mode, options)
1160
+ if mode == :default
1161
+ # This module is being added as a default tracer. If any other mode classes
1162
+ # have already been created, but get their default behavior from a superclass,
1163
+ # Then mix this into this schema's subclass.
1164
+ # (But don't mix it into mode classes that aren't default-based.)
1165
+ own_trace_modes.each do |other_mode_name, other_mode_class|
1166
+ if other_mode_class < DefaultTraceClass
1167
+ # Don't add it back to the inheritance tree if it's already there
1168
+ if !(other_mode_class < trace_mod)
1169
+ other_mode_class.include(trace_mod)
1170
+ end
1171
+ # Add any options so they'll be available
1172
+ add_trace_options_for(other_mode_name, options)
1173
+ end
1174
+ end
1175
+ end
1608
1176
  end
1609
- own_query_analyzers << new_analyzer
1177
+ nil
1610
1178
  end
1611
1179
 
1612
- def query_analyzers
1613
- find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1180
+ # The options hash for this trace mode
1181
+ # @return [Hash]
1182
+ def trace_options_for(mode)
1183
+ @trace_options_for_mode ||= {}
1184
+ @trace_options_for_mode[mode] ||= begin
1185
+ # It may be time to create an options hash for a mode that wasn't registered yet.
1186
+ # Mix in the default options in that case.
1187
+ default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
1188
+ # Make sure this returns a new object so that other hashes aren't modified later
1189
+ if superclass.respond_to?(:trace_options_for)
1190
+ superclass.trace_options_for(mode).merge(default_options)
1191
+ else
1192
+ default_options.dup
1193
+ end
1194
+ end
1614
1195
  end
1615
1196
 
1616
- def middleware(new_middleware = nil)
1617
- if new_middleware
1618
- GraphQL::Deprecation.warn "Middleware will be removed in GraphQL-Ruby 2.0, please upgrade to Field Extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1619
- own_middleware << new_middleware
1197
+ # Create a trace instance which will include the trace modules specified for the optional mode.
1198
+ #
1199
+ # If no `mode:` is given, then {default_trace_mode} will be used.
1200
+ #
1201
+ # @param mode [Symbol] Trace modules for this trade mode will be included
1202
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1203
+ # @return [Tracing::Trace]
1204
+ def new_trace(mode: nil, **options)
1205
+ target = options[:query] || options[:multiplex]
1206
+ mode ||= target && target.context[:trace_mode]
1207
+
1208
+ trace_mode = if mode
1209
+ mode
1210
+ elsif target && target.context[:backtrace]
1211
+ if default_trace_mode != :default
1212
+ raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
1213
+ else
1214
+ own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
1215
+ options_trace_mode = :default
1216
+ :default_backtrace
1217
+ end
1620
1218
  else
1621
- # TODO make sure this is cached when running a query
1622
- MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
1219
+ default_trace_mode
1623
1220
  end
1221
+
1222
+ options_trace_mode ||= trace_mode
1223
+ base_trace_options = trace_options_for(options_trace_mode)
1224
+ trace_options = base_trace_options.merge(options)
1225
+ trace_class_for_mode = trace_class_for(trace_mode, build: true)
1226
+ trace_class_for_mode.new(**trace_options)
1227
+ end
1228
+
1229
+ def query_analyzer(new_analyzer)
1230
+ own_query_analyzers << new_analyzer
1231
+ end
1232
+
1233
+ def query_analyzers
1234
+ find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1624
1235
  end
1625
1236
 
1626
1237
  def multiplex_analyzer(new_analyzer)
@@ -1631,6 +1242,14 @@ module GraphQL
1631
1242
  find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1632
1243
  end
1633
1244
 
1245
+ def sanitized_printer(new_sanitized_printer = nil)
1246
+ if new_sanitized_printer
1247
+ @own_sanitized_printer = new_sanitized_printer
1248
+ else
1249
+ @own_sanitized_printer || GraphQL::Language::SanitizedPrinter
1250
+ end
1251
+ end
1252
+
1634
1253
  # Execute a query on itself.
1635
1254
  # @see {Query#initialize} for arguments.
1636
1255
  # @return [Hash] query result, ready to be serialized as JSON
@@ -1643,6 +1262,9 @@ module GraphQL
1643
1262
  {
1644
1263
  backtrace: ctx[:backtrace],
1645
1264
  tracers: ctx[:tracers],
1265
+ trace: ctx[:trace],
1266
+ dataloader: ctx[:dataloader],
1267
+ trace_mode: ctx[:trace_mode],
1646
1268
  }
1647
1269
  else
1648
1270
  {}
@@ -1667,17 +1289,12 @@ module GraphQL
1667
1289
  # }
1668
1290
  #
1669
1291
  # @see {Query#initialize} for query keyword arguments
1670
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
1292
+ # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
1671
1293
  # @param queries [Array<Hash>] Keyword arguments for each query
1672
1294
  # @param context [Hash] Multiplex-level context
1673
1295
  # @return [Array<Hash>] One result for each query in the input
1674
1296
  def multiplex(queries, **kwargs)
1675
- schema = if interpreter?
1676
- self
1677
- else
1678
- graphql_definition
1679
- end
1680
- GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
1297
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1681
1298
  end
1682
1299
 
1683
1300
  def instrumenters
@@ -1689,12 +1306,10 @@ module GraphQL
1689
1306
 
1690
1307
  # @api private
1691
1308
  def add_subscription_extension_if_necessary
1692
- if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1309
+ if !defined?(@subscription_extension_added) && subscription && self.subscriptions
1693
1310
  @subscription_extension_added = true
1694
- if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1695
- GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1696
- else
1697
- subscription.fields.each do |name, field|
1311
+ subscription.all_field_definitions.each do |field|
1312
+ if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
1698
1313
  field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1699
1314
  end
1700
1315
  end
@@ -1705,8 +1320,68 @@ module GraphQL
1705
1320
  query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1706
1321
  end
1707
1322
 
1323
+ # Call the given block at the right time, either:
1324
+ # - Right away, if `value` is not registered with `lazy_resolve`
1325
+ # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1326
+ # @api private
1327
+ def after_lazy(value, &block)
1328
+ if lazy?(value)
1329
+ GraphQL::Execution::Lazy.new do
1330
+ result = sync_lazy(value)
1331
+ # The returned result might also be lazy, so check it, too
1332
+ after_lazy(result, &block)
1333
+ end
1334
+ else
1335
+ yield(value) if block_given?
1336
+ end
1337
+ end
1338
+
1339
+ # Override this method to handle lazy objects in a custom way.
1340
+ # @param value [Object] an instance of a class registered with {.lazy_resolve}
1341
+ # @return [Object] A GraphQL-ready (non-lazy) object
1342
+ # @api private
1343
+ def sync_lazy(value)
1344
+ lazy_method = lazy_method_name(value)
1345
+ if lazy_method
1346
+ synced_value = value.public_send(lazy_method)
1347
+ sync_lazy(synced_value)
1348
+ else
1349
+ value
1350
+ end
1351
+ end
1352
+
1353
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
1354
+ def lazy_method_name(obj)
1355
+ lazy_methods.get(obj)
1356
+ end
1357
+
1358
+ # @return [Boolean] True if this object should be lazily resolved
1359
+ def lazy?(obj)
1360
+ !!lazy_method_name(obj)
1361
+ end
1362
+
1363
+ # Return a lazy if any of `maybe_lazies` are lazy,
1364
+ # otherwise, call the block eagerly and return the result.
1365
+ # @param maybe_lazies [Array]
1366
+ # @api private
1367
+ def after_any_lazies(maybe_lazies)
1368
+ if maybe_lazies.any? { |l| lazy?(l) }
1369
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
1370
+ yield result
1371
+ end
1372
+ else
1373
+ yield maybe_lazies
1374
+ end
1375
+ end
1376
+
1708
1377
  private
1709
1378
 
1379
+ def add_trace_options_for(mode, new_options)
1380
+ t_opts = trace_options_for(mode)
1381
+ t_opts.merge!(new_options)
1382
+ nil
1383
+ end
1384
+
1710
1385
  # @param t [Module, Array<Module>]
1711
1386
  # @return [void]
1712
1387
  def add_type_and_traverse(t, root:)
@@ -1716,7 +1391,36 @@ module GraphQL
1716
1391
  end
1717
1392
  new_types = Array(t)
1718
1393
  addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1719
- own_types.merge!(addition.types)
1394
+ addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
1395
+ if (prev_entry = own_types[name])
1396
+ prev_entries = case prev_entry
1397
+ when Array
1398
+ prev_entry
1399
+ when Module
1400
+ own_types[name] = [prev_entry]
1401
+ else
1402
+ raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
1403
+ end
1404
+
1405
+ case types_entry
1406
+ when Array
1407
+ prev_entries.concat(types_entry)
1408
+ prev_entries.uniq! # in case any are being re-visited
1409
+ when Module
1410
+ if !prev_entries.include?(types_entry)
1411
+ prev_entries << types_entry
1412
+ end
1413
+ else
1414
+ raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
1415
+ end
1416
+ else
1417
+ if types_entry.is_a?(Array)
1418
+ types_entry.uniq!
1419
+ end
1420
+ own_types[name] = types_entry
1421
+ end
1422
+ end
1423
+
1720
1424
  own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1721
1425
  own_union_memberships.merge!(addition.union_memberships)
1722
1426
 
@@ -1739,7 +1443,7 @@ module GraphQL
1739
1443
  else
1740
1444
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1741
1445
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1742
- @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1446
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
1743
1447
  end
1744
1448
  end
1745
1449
  @lazy_methods
@@ -1785,68 +1489,33 @@ module GraphQL
1785
1489
  @defined_query_analyzers ||= []
1786
1490
  end
1787
1491
 
1788
- def all_middleware
1789
- find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1790
- end
1791
-
1792
- def own_middleware
1793
- @own_middleware ||= []
1794
- end
1795
-
1796
1492
  def own_multiplex_analyzers
1797
1493
  @own_multiplex_analyzers ||= []
1798
1494
  end
1799
- end
1800
-
1801
- def dataloader_class
1802
- self.class.dataloader_class
1803
- end
1804
-
1805
- # Install these here so that subclasses will also install it.
1806
- use(GraphQL::Pagination::Connections)
1807
-
1808
- protected
1809
1495
 
1810
- def rescues?
1811
- !!@rescue_middleware
1812
- end
1813
-
1814
- # Lazily create a middleware and add it to the schema
1815
- # (Don't add it if it's not used)
1816
- def rescue_middleware
1817
- @rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
1818
- end
1819
-
1820
- private
1821
-
1822
- def rebuild_artifacts
1823
- if @rebuilding_artifacts
1824
- raise CyclicalDefinitionError, "Part of the schema build process re-triggered the schema build process, causing an infinite loop. Avoid using Schema#types, Schema#possible_types, and Schema#get_field during schema build."
1825
- else
1826
- @rebuilding_artifacts = true
1827
- @introspection_system = Schema::IntrospectionSystem.new(self)
1828
- traversal = Traversal.new(self)
1829
- @types = traversal.type_map
1830
- @root_types = [query, mutation, subscription]
1831
- @instrumented_field_map = traversal.instrumented_field_map
1832
- @type_reference_map = traversal.type_reference_map
1833
- @union_memberships = traversal.union_memberships
1834
- @find_cache = {}
1835
- @finder = Finder.new(self)
1836
- end
1837
- ensure
1838
- @rebuilding_artifacts = false
1839
- end
1840
-
1841
- class CyclicalDefinitionError < GraphQL::Error
1496
+ # This is overridden in subclasses to check the inheritance chain
1497
+ def get_references_to(type_name)
1498
+ @own_references_to[type_name]
1499
+ end
1842
1500
  end
1843
1501
 
1844
- def with_definition_error_check
1845
- if @definition_error
1846
- raise @definition_error
1847
- else
1848
- yield
1502
+ module SubclassGetReferencesTo
1503
+ def get_references_to(type_name)
1504
+ own_refs = @own_references_to[type_name]
1505
+ inherited_refs = superclass.references_to(type_name)
1506
+ if inherited_refs&.any?
1507
+ if own_refs&.any?
1508
+ own_refs + inherited_refs
1509
+ else
1510
+ inherited_refs
1511
+ end
1512
+ else
1513
+ own_refs
1514
+ end
1849
1515
  end
1850
1516
  end
1517
+
1518
+ # Install these here so that subclasses will also install it.
1519
+ self.connections = GraphQL::Pagination::Connections.new(schema: self)
1851
1520
  end
1852
1521
  end