graphql 1.10.2 → 2.0.21

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 (402) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +21 -10
  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 +45 -8
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +49 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +2 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  28. data/lib/generators/graphql/templates/base_object.erb +2 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +24 -33
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/ast/field_usage.rb +30 -1
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +125 -117
  51. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  52. data/lib/graphql/analysis/ast/visitor.rb +52 -36
  53. data/lib/graphql/analysis/ast.rb +7 -8
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  56. data/lib/graphql/backtrace/table.rb +31 -18
  57. data/lib/graphql/backtrace/trace.rb +96 -0
  58. data/lib/graphql/backtrace/traced_error.rb +0 -1
  59. data/lib/graphql/backtrace/tracer.rb +39 -9
  60. data/lib/graphql/backtrace.rb +26 -18
  61. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  62. data/lib/graphql/dataloader/request.rb +19 -0
  63. data/lib/graphql/dataloader/request_all.rb +19 -0
  64. data/lib/graphql/dataloader/source.rb +164 -0
  65. data/lib/graphql/dataloader.rb +311 -0
  66. data/lib/graphql/date_encoding_error.rb +16 -0
  67. data/lib/graphql/deprecation.rb +9 -0
  68. data/lib/graphql/dig.rb +1 -1
  69. data/lib/graphql/execution/errors.rb +77 -44
  70. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  71. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  72. data/lib/graphql/execution/interpreter/arguments_cache.rb +104 -0
  73. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  74. data/lib/graphql/execution/interpreter/resolve.rb +62 -24
  75. data/lib/graphql/execution/interpreter/runtime.rb +826 -464
  76. data/lib/graphql/execution/interpreter.rb +206 -68
  77. data/lib/graphql/execution/lazy.rb +11 -21
  78. data/lib/graphql/execution/lookahead.rb +55 -136
  79. data/lib/graphql/execution/multiplex.rb +6 -162
  80. data/lib/graphql/execution.rb +11 -4
  81. data/lib/graphql/filter.rb +7 -2
  82. data/lib/graphql/integer_decoding_error.rb +17 -0
  83. data/lib/graphql/integer_encoding_error.rb +18 -2
  84. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  85. data/lib/graphql/introspection/directive_type.rb +11 -5
  86. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  87. data/lib/graphql/introspection/entry_points.rb +4 -17
  88. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  89. data/lib/graphql/introspection/field_type.rb +9 -5
  90. data/lib/graphql/introspection/input_value_type.rb +15 -3
  91. data/lib/graphql/introspection/introspection_query.rb +6 -92
  92. data/lib/graphql/introspection/schema_type.rb +11 -6
  93. data/lib/graphql/introspection/type_type.rb +31 -14
  94. data/lib/graphql/introspection.rb +100 -0
  95. data/lib/graphql/invalid_null_error.rb +18 -0
  96. data/lib/graphql/language/block_string.rb +20 -5
  97. data/lib/graphql/language/cache.rb +37 -0
  98. data/lib/graphql/language/document_from_schema_definition.rb +96 -44
  99. data/lib/graphql/language/lexer.rb +216 -1462
  100. data/lib/graphql/language/nodes.rb +126 -129
  101. data/lib/graphql/language/parser.rb +997 -933
  102. data/lib/graphql/language/parser.y +148 -118
  103. data/lib/graphql/language/printer.rb +48 -23
  104. data/lib/graphql/language/sanitized_printer.rb +222 -0
  105. data/lib/graphql/language/token.rb +0 -4
  106. data/lib/graphql/language/visitor.rb +192 -84
  107. data/lib/graphql/language.rb +2 -0
  108. data/lib/graphql/name_validator.rb +2 -7
  109. data/lib/graphql/pagination/active_record_relation_connection.rb +45 -3
  110. data/lib/graphql/pagination/array_connection.rb +6 -4
  111. data/lib/graphql/pagination/connection.rb +105 -23
  112. data/lib/graphql/pagination/connections.rb +62 -35
  113. data/lib/graphql/pagination/relation_connection.rb +88 -36
  114. data/lib/graphql/parse_error.rb +0 -1
  115. data/lib/graphql/query/context.rb +203 -198
  116. data/lib/graphql/query/fingerprint.rb +26 -0
  117. data/lib/graphql/query/input_validation_result.rb +33 -7
  118. data/lib/graphql/query/null_context.rb +22 -9
  119. data/lib/graphql/query/validation_pipeline.rb +16 -38
  120. data/lib/graphql/query/variable_validation_error.rb +3 -3
  121. data/lib/graphql/query/variables.rb +36 -12
  122. data/lib/graphql/query.rb +92 -44
  123. data/lib/graphql/railtie.rb +6 -102
  124. data/lib/graphql/rake_task/validate.rb +1 -1
  125. data/lib/graphql/rake_task.rb +41 -10
  126. data/lib/graphql/relay/range_add.rb +17 -10
  127. data/lib/graphql/relay.rb +0 -15
  128. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  129. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  130. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  131. data/lib/graphql/rubocop.rb +4 -0
  132. data/lib/graphql/schema/addition.rb +245 -0
  133. data/lib/graphql/schema/argument.rb +250 -46
  134. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  135. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  136. data/lib/graphql/schema/build_from_definition.rb +243 -89
  137. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  138. data/lib/graphql/schema/directive/feature.rb +1 -1
  139. data/lib/graphql/schema/directive/flagged.rb +57 -0
  140. data/lib/graphql/schema/directive/include.rb +1 -1
  141. data/lib/graphql/schema/directive/one_of.rb +12 -0
  142. data/lib/graphql/schema/directive/skip.rb +1 -1
  143. data/lib/graphql/schema/directive/transform.rb +14 -2
  144. data/lib/graphql/schema/directive.rb +108 -20
  145. data/lib/graphql/schema/enum.rb +105 -44
  146. data/lib/graphql/schema/enum_value.rb +15 -25
  147. data/lib/graphql/schema/field/connection_extension.rb +50 -30
  148. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  149. data/lib/graphql/schema/field.rb +476 -331
  150. data/lib/graphql/schema/field_extension.rb +86 -2
  151. data/lib/graphql/schema/find_inherited_value.rb +6 -8
  152. data/lib/graphql/schema/finder.rb +5 -5
  153. data/lib/graphql/schema/input_object.rb +133 -121
  154. data/lib/graphql/schema/interface.rb +17 -45
  155. data/lib/graphql/schema/introspection_system.rb +3 -8
  156. data/lib/graphql/schema/late_bound_type.rb +8 -2
  157. data/lib/graphql/schema/list.rb +25 -8
  158. data/lib/graphql/schema/loader.rb +139 -103
  159. data/lib/graphql/schema/member/base_dsl_methods.rb +29 -35
  160. data/lib/graphql/schema/member/build_type.rb +19 -14
  161. data/lib/graphql/schema/member/has_arguments.rb +310 -26
  162. data/lib/graphql/schema/member/has_ast_node.rb +16 -1
  163. data/lib/graphql/schema/member/has_deprecation_reason.rb +24 -0
  164. data/lib/graphql/schema/member/has_directives.rb +118 -0
  165. data/lib/graphql/schema/member/has_fields.rb +164 -42
  166. data/lib/graphql/schema/member/has_interfaces.rb +129 -0
  167. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  168. data/lib/graphql/schema/member/has_validators.rb +57 -0
  169. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  170. data/lib/graphql/schema/member/type_system_helpers.rb +20 -3
  171. data/lib/graphql/schema/member/validates_input.rb +3 -3
  172. data/lib/graphql/schema/member.rb +6 -6
  173. data/lib/graphql/schema/mutation.rb +4 -9
  174. data/lib/graphql/schema/non_null.rb +12 -7
  175. data/lib/graphql/schema/object.rb +35 -69
  176. data/lib/graphql/schema/printer.rb +16 -34
  177. data/lib/graphql/schema/relay_classic_mutation.rb +90 -43
  178. data/lib/graphql/schema/resolver/has_payload_type.rb +51 -11
  179. data/lib/graphql/schema/resolver.rb +144 -79
  180. data/lib/graphql/schema/scalar.rb +27 -18
  181. data/lib/graphql/schema/subscription.rb +55 -26
  182. data/lib/graphql/schema/timeout.rb +45 -35
  183. data/lib/graphql/schema/type_expression.rb +1 -1
  184. data/lib/graphql/schema/type_membership.rb +21 -4
  185. data/lib/graphql/schema/union.rb +48 -13
  186. data/lib/graphql/schema/unique_within_type.rb +1 -2
  187. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  188. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  189. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  190. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  191. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  192. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  193. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  194. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  195. data/lib/graphql/schema/validator.rb +171 -0
  196. data/lib/graphql/schema/warden.rb +185 -32
  197. data/lib/graphql/schema/wrapper.rb +0 -5
  198. data/lib/graphql/schema.rb +471 -1116
  199. data/lib/graphql/static_validation/all_rules.rb +3 -0
  200. data/lib/graphql/static_validation/base_visitor.rb +13 -27
  201. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  202. data/lib/graphql/static_validation/error.rb +3 -1
  203. data/lib/graphql/static_validation/literal_validator.rb +69 -26
  204. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
  205. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  206. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
  207. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  208. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
  209. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
  210. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  211. data/lib/graphql/static_validation/rules/fields_will_merge.rb +92 -49
  212. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  213. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  214. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  215. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  216. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  217. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  218. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  219. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  220. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  221. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
  222. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  223. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
  224. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  225. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  226. data/lib/graphql/static_validation/validation_context.rb +13 -3
  227. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  228. data/lib/graphql/static_validation/validator.rb +32 -20
  229. data/lib/graphql/static_validation.rb +1 -2
  230. data/lib/graphql/string_encoding_error.rb +13 -3
  231. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +126 -19
  232. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  233. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  234. data/lib/graphql/subscriptions/event.rb +81 -35
  235. data/lib/graphql/subscriptions/instrumentation.rb +0 -52
  236. data/lib/graphql/subscriptions/serialize.rb +53 -6
  237. data/lib/graphql/subscriptions.rb +113 -58
  238. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  239. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
  240. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  241. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  242. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  243. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  244. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  245. data/lib/graphql/tracing/data_dog_tracing.rb +26 -2
  246. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  247. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  248. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  249. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  250. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  251. data/lib/graphql/tracing/platform_trace.rb +109 -0
  252. data/lib/graphql/tracing/platform_tracing.rb +64 -43
  253. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  254. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +5 -2
  255. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  256. data/lib/graphql/tracing/scout_trace.rb +72 -0
  257. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  258. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  259. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  260. data/lib/graphql/tracing/trace.rb +75 -0
  261. data/lib/graphql/tracing.rb +23 -71
  262. data/lib/graphql/type_kinds.rb +6 -3
  263. data/lib/graphql/types/big_int.rb +5 -1
  264. data/lib/graphql/types/int.rb +10 -3
  265. data/lib/graphql/types/iso_8601_date.rb +20 -9
  266. data/lib/graphql/types/iso_8601_date_time.rb +36 -10
  267. data/lib/graphql/types/relay/base_connection.rb +18 -92
  268. data/lib/graphql/types/relay/base_edge.rb +2 -34
  269. data/lib/graphql/types/relay/connection_behaviors.rb +176 -0
  270. data/lib/graphql/types/relay/edge_behaviors.rb +75 -0
  271. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  272. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  273. data/lib/graphql/types/relay/node.rb +2 -4
  274. data/lib/graphql/types/relay/node_behaviors.rb +25 -0
  275. data/lib/graphql/types/relay/page_info.rb +2 -14
  276. data/lib/graphql/types/relay/page_info_behaviors.rb +30 -0
  277. data/lib/graphql/types/relay.rb +10 -5
  278. data/lib/graphql/types/string.rb +8 -2
  279. data/lib/graphql/unauthorized_error.rb +2 -2
  280. data/lib/graphql/version.rb +1 -1
  281. data/lib/graphql.rb +54 -65
  282. data/readme.md +3 -6
  283. metadata +116 -236
  284. data/lib/graphql/analysis/analyze_query.rb +0 -91
  285. data/lib/graphql/analysis/field_usage.rb +0 -45
  286. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  287. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  288. data/lib/graphql/analysis/query_complexity.rb +0 -88
  289. data/lib/graphql/analysis/query_depth.rb +0 -43
  290. data/lib/graphql/analysis/reducer_state.rb +0 -48
  291. data/lib/graphql/argument.rb +0 -131
  292. data/lib/graphql/authorization.rb +0 -82
  293. data/lib/graphql/backwards_compatibility.rb +0 -60
  294. data/lib/graphql/base_type.rb +0 -230
  295. data/lib/graphql/boolean_type.rb +0 -2
  296. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  297. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  298. data/lib/graphql/compatibility/execution_specification.rb +0 -435
  299. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  300. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
  301. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  302. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  303. data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
  304. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
  305. data/lib/graphql/compatibility.rb +0 -5
  306. data/lib/graphql/define/assign_argument.rb +0 -12
  307. data/lib/graphql/define/assign_connection.rb +0 -13
  308. data/lib/graphql/define/assign_enum_value.rb +0 -18
  309. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  310. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  311. data/lib/graphql/define/assign_object_field.rb +0 -42
  312. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  313. data/lib/graphql/define/instance_definable.rb +0 -210
  314. data/lib/graphql/define/no_definition_error.rb +0 -7
  315. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  316. data/lib/graphql/define/type_definer.rb +0 -31
  317. data/lib/graphql/define.rb +0 -31
  318. data/lib/graphql/deprecated_dsl.rb +0 -42
  319. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  320. data/lib/graphql/directive/include_directive.rb +0 -2
  321. data/lib/graphql/directive/skip_directive.rb +0 -2
  322. data/lib/graphql/directive.rb +0 -107
  323. data/lib/graphql/enum_type.rb +0 -127
  324. data/lib/graphql/execution/execute.rb +0 -326
  325. data/lib/graphql/execution/flatten.rb +0 -40
  326. data/lib/graphql/execution/instrumentation.rb +0 -92
  327. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  328. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  329. data/lib/graphql/execution/typecast.rb +0 -50
  330. data/lib/graphql/field/resolve.rb +0 -59
  331. data/lib/graphql/field.rb +0 -222
  332. data/lib/graphql/float_type.rb +0 -2
  333. data/lib/graphql/function.rb +0 -124
  334. data/lib/graphql/id_type.rb +0 -2
  335. data/lib/graphql/input_object_type.rb +0 -132
  336. data/lib/graphql/int_type.rb +0 -2
  337. data/lib/graphql/interface_type.rb +0 -65
  338. data/lib/graphql/internal_representation/document.rb +0 -27
  339. data/lib/graphql/internal_representation/node.rb +0 -206
  340. data/lib/graphql/internal_representation/print.rb +0 -51
  341. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  342. data/lib/graphql/internal_representation/scope.rb +0 -88
  343. data/lib/graphql/internal_representation/visit.rb +0 -36
  344. data/lib/graphql/internal_representation.rb +0 -7
  345. data/lib/graphql/language/lexer.rl +0 -258
  346. data/lib/graphql/list_type.rb +0 -80
  347. data/lib/graphql/literal_validation_error.rb +0 -6
  348. data/lib/graphql/non_null_type.rb +0 -71
  349. data/lib/graphql/object_type.rb +0 -121
  350. data/lib/graphql/query/arguments.rb +0 -188
  351. data/lib/graphql/query/arguments_cache.rb +0 -25
  352. data/lib/graphql/query/executor.rb +0 -53
  353. data/lib/graphql/query/literal_input.rb +0 -136
  354. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  355. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  356. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  357. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  358. data/lib/graphql/query/serial_execution.rb +0 -39
  359. data/lib/graphql/relay/array_connection.rb +0 -85
  360. data/lib/graphql/relay/base_connection.rb +0 -176
  361. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  362. data/lib/graphql/relay/connection_resolve.rb +0 -43
  363. data/lib/graphql/relay/connection_type.rb +0 -41
  364. data/lib/graphql/relay/edge.rb +0 -27
  365. data/lib/graphql/relay/edge_type.rb +0 -19
  366. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  367. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  368. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  369. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  370. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  371. data/lib/graphql/relay/mutation/result.rb +0 -38
  372. data/lib/graphql/relay/mutation.rb +0 -105
  373. data/lib/graphql/relay/node.rb +0 -36
  374. data/lib/graphql/relay/page_info.rb +0 -7
  375. data/lib/graphql/relay/relation_connection.rb +0 -190
  376. data/lib/graphql/relay/type_extensions.rb +0 -30
  377. data/lib/graphql/scalar_type.rb +0 -76
  378. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  379. data/lib/graphql/schema/default_parse_error.rb +0 -10
  380. data/lib/graphql/schema/default_type_error.rb +0 -15
  381. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  382. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  383. data/lib/graphql/schema/member/instrumentation.rb +0 -132
  384. data/lib/graphql/schema/middleware_chain.rb +0 -82
  385. data/lib/graphql/schema/possible_types.rb +0 -39
  386. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  387. data/lib/graphql/schema/timeout_middleware.rb +0 -86
  388. data/lib/graphql/schema/traversal.rb +0 -228
  389. data/lib/graphql/schema/validation.rb +0 -303
  390. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  391. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  392. data/lib/graphql/string_type.rb +0 -2
  393. data/lib/graphql/subscriptions/subscription_root.rb +0 -65
  394. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  395. data/lib/graphql/types/relay/base_field.rb +0 -22
  396. data/lib/graphql/types/relay/base_interface.rb +0 -29
  397. data/lib/graphql/types/relay/base_object.rb +0 -26
  398. data/lib/graphql/types/relay/node_field.rb +0 -43
  399. data/lib/graphql/types/relay/nodes_field.rb +0 -45
  400. data/lib/graphql/union_type.rb +0 -113
  401. data/lib/graphql/upgrader/member.rb +0 -936
  402. data/lib/graphql/upgrader/schema.rb +0 -37
@@ -1,26 +1,19 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/schema/addition"
2
3
  require "graphql/schema/base_64_encoder"
3
- require "graphql/schema/catchall_middleware"
4
- require "graphql/schema/default_parse_error"
5
- require "graphql/schema/default_type_error"
6
4
  require "graphql/schema/find_inherited_value"
7
5
  require "graphql/schema/finder"
8
6
  require "graphql/schema/invalid_type_error"
9
7
  require "graphql/schema/introspection_system"
10
8
  require "graphql/schema/late_bound_type"
11
- require "graphql/schema/middleware_chain"
12
9
  require "graphql/schema/null_mask"
13
- require "graphql/schema/possible_types"
14
- require "graphql/schema/rescue_middleware"
15
10
  require "graphql/schema/timeout"
16
- require "graphql/schema/timeout_middleware"
17
- require "graphql/schema/traversal"
18
11
  require "graphql/schema/type_expression"
19
12
  require "graphql/schema/unique_within_type"
20
- require "graphql/schema/validation"
21
13
  require "graphql/schema/warden"
22
14
  require "graphql/schema/build_from_definition"
23
15
 
16
+ require "graphql/schema/validator"
24
17
  require "graphql/schema/member"
25
18
  require "graphql/schema/wrapper"
26
19
  require "graphql/schema/list"
@@ -38,8 +31,10 @@ require "graphql/schema/union"
38
31
  require "graphql/schema/directive"
39
32
  require "graphql/schema/directive/deprecated"
40
33
  require "graphql/schema/directive/include"
34
+ require "graphql/schema/directive/one_of"
41
35
  require "graphql/schema/directive/skip"
42
36
  require "graphql/schema/directive/feature"
37
+ require "graphql/schema/directive/flagged"
43
38
  require "graphql/schema/directive/transform"
44
39
  require "graphql/schema/type_membership"
45
40
 
@@ -67,7 +62,7 @@ module GraphQL
67
62
  # Schemas can specify how queries should be executed against them.
68
63
  # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
69
64
  # each apply to corresponding root types.
70
- # #
65
+ #
71
66
  # @example defining a schema
72
67
  # class MySchema < GraphQL::Schema
73
68
  # query QueryType
@@ -76,12 +71,19 @@ module GraphQL
76
71
  # end
77
72
  #
78
73
  class Schema
79
- extend Forwardable
80
- extend GraphQL::Schema::Member::AcceptsDefinition
81
74
  extend GraphQL::Schema::Member::HasAstNode
82
- include GraphQL::Define::InstanceDefinable
83
75
  extend GraphQL::Schema::FindInheritedValue
84
76
 
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
+ )
84
+ end
85
+ end
86
+
85
87
  class UnresolvedLateBoundTypeError < GraphQL::Error
86
88
  attr_reader :type
87
89
  def initialize(type:)
@@ -90,727 +92,121 @@ module GraphQL
90
92
  end
91
93
  end
92
94
 
93
- accepts_definitions \
94
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
95
- :max_depth, :max_complexity, :default_max_page_size,
96
- :orphan_types, :resolve_type, :type_error, :parse_error,
97
- :error_bubbling,
98
- :raise_definition_error,
99
- :object_from_id, :id_from_object,
100
- :default_mask,
101
- :cursor_encoder,
102
- # If these are given as classes, normalize them. Accept `nil` when building from string.
103
- query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
104
- mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
105
- subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
106
- disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
107
- disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
108
- disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
109
- directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
110
- directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
111
- instrument: ->(schema, type, instrumenter, after_built_ins: false) {
112
- if type == :field && after_built_ins
113
- type = :field_after_built_ins
114
- end
115
- schema.instrumenters[type] << instrumenter
116
- },
117
- query_analyzer: ->(schema, analyzer) {
118
- if analyzer == GraphQL::Authorization::Analyzer
119
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
120
- end
121
- schema.query_analyzers << analyzer
122
- },
123
- multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
124
- middleware: ->(schema, middleware) { schema.middleware << middleware },
125
- lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
126
- rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
127
- tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
128
-
129
- ensure_defined :introspection_system
130
-
131
- attr_accessor \
132
- :query, :mutation, :subscription,
133
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
134
- :max_depth, :max_complexity, :default_max_page_size,
135
- :orphan_types, :directives,
136
- :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
137
- :cursor_encoder,
138
- :ast_node,
139
- :raise_definition_error,
140
- :introspection_namespace,
141
- :analysis_engine
142
-
143
- # [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
144
- attr_accessor :error_bubbling
145
-
146
- # Single, long-lived instance of the provided subscriptions class, if there is one.
147
- # @return [GraphQL::Subscriptions]
148
- attr_accessor :subscriptions
149
-
150
- # @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
151
- attr_accessor :middleware
152
-
153
- # @return [<#call(member, ctx)>] A callable for filtering members of the schema
154
- # @see {Query.new} for query-specific filters with `except:`
155
- attr_accessor :default_mask
156
-
157
- # @see {GraphQL::Query::Context} The parent class of these classes
158
- # @return [Class] Instantiated for each query
159
- attr_accessor :context_class
160
-
161
- # [Boolean] True if this object disables the introspection entry point fields
162
- attr_accessor :disable_introspection_entry_points
163
-
164
- def disable_introspection_entry_points?
165
- !!@disable_introspection_entry_points
166
- end
167
-
168
- # [Boolean] True if this object disables the __schema introspection entry point field
169
- attr_accessor :disable_schema_introspection_entry_point
170
-
171
- def disable_schema_introspection_entry_point?
172
- !!@disable_schema_introspection_entry_point
173
- end
174
-
175
- # [Boolean] True if this object disables the __type introspection entry point field
176
- attr_accessor :disable_type_introspection_entry_point
177
-
178
- def disable_type_introspection_entry_point?
179
- !!@disable_type_introspection_entry_point
180
- end
95
+ # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
96
+ class InvalidDocumentError < Error; end;
181
97
 
182
98
  class << self
183
- attr_writer :default_execution_strategy
184
- end
185
-
186
- def default_filter
187
- GraphQL::Filter.new(except: default_mask)
188
- end
189
-
190
- # @return [Array<#trace(key, data)>] Tracers applied to every query
191
- # @see {Query#tracers} for query-specific tracers
192
- attr_reader :tracers
193
-
194
- DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
195
-
196
- attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
197
-
198
- def initialize
199
- @tracers = []
200
- @definition_error = nil
201
- @orphan_types = []
202
- @directives = {}
203
- self.class.default_directives.each do |name, dir|
204
- @directives[name] = dir.graphql_definition
205
- end
206
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
207
- @middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
208
- @query_analyzers = []
209
- @multiplex_analyzers = []
210
- @resolve_type_proc = nil
211
- @object_from_id_proc = nil
212
- @id_from_object_proc = nil
213
- @type_error_proc = DefaultTypeError
214
- @parse_error_proc = DefaultParseError
215
- @instrumenters = Hash.new { |h, k| h[k] = [] }
216
- @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
217
- @lazy_methods.set(GraphQL::Execution::Lazy, :value)
218
- @cursor_encoder = Base64Encoder
219
- # Default to the built-in execution strategy:
220
- @analysis_engine = GraphQL::Analysis
221
- @query_execution_strategy = self.class.default_execution_strategy
222
- @mutation_execution_strategy = self.class.default_execution_strategy
223
- @subscription_execution_strategy = self.class.default_execution_strategy
224
- @default_mask = GraphQL::Schema::NullMask
225
- @rebuilding_artifacts = false
226
- @context_class = GraphQL::Query::Context
227
- @introspection_namespace = nil
228
- @introspection_system = nil
229
- @interpreter = false
230
- @error_bubbling = false
231
- @disable_introspection_entry_points = false
232
- @disable_schema_introspection_entry_point = false
233
- @disable_type_introspection_entry_point = false
234
- end
235
-
236
- # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
237
- def interpreter?
238
- @interpreter
239
- end
240
-
241
- # @api private
242
- attr_writer :interpreter
243
-
244
- def inspect
245
- "#<#{self.class.name} ...>"
246
- end
247
-
248
- def initialize_copy(other)
249
- super
250
- @orphan_types = other.orphan_types.dup
251
- @directives = other.directives.dup
252
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
253
- @middleware = other.middleware.dup
254
- @query_analyzers = other.query_analyzers.dup
255
- @multiplex_analyzers = other.multiplex_analyzers.dup
256
- @tracers = other.tracers.dup
257
- @possible_types = GraphQL::Schema::PossibleTypes.new(self)
258
-
259
- @lazy_methods = other.lazy_methods.dup
260
-
261
- @instrumenters = Hash.new { |h, k| h[k] = [] }
262
- other.instrumenters.each do |key, insts|
263
- @instrumenters[key].concat(insts)
264
- end
265
-
266
- if other.rescues?
267
- @rescue_middleware = other.rescue_middleware
268
- end
269
-
270
- # This will be rebuilt when it's requested
271
- # or during a later `define` call
272
- @types = nil
273
- @introspection_system = nil
274
- end
275
-
276
- def rescue_from(*args, &block)
277
- rescue_middleware.rescue_from(*args, &block)
278
- end
279
-
280
- def remove_handler(*args, &block)
281
- rescue_middleware.remove_handler(*args, &block)
282
- end
283
-
284
- def using_ast_analysis?
285
- @analysis_engine == GraphQL::Analysis::AST
286
- end
287
-
288
- # For forwards-compatibility with Schema classes
289
- alias :graphql_definition :itself
290
-
291
- # Validate a query string according to this schema.
292
- # @param string_or_document [String, GraphQL::Language::Nodes::Document]
293
- # @return [Array<GraphQL::StaticValidation::Error >]
294
- def validate(string_or_document, rules: nil, context: nil)
295
- doc = if string_or_document.is_a?(String)
296
- GraphQL.parse(string_or_document)
297
- else
298
- string_or_document
299
- end
300
- query = GraphQL::Query.new(self, document: doc, context: context)
301
- validator_opts = { schema: self }
302
- rules && (validator_opts[:rules] = rules)
303
- validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
304
- res = validator.validate(query)
305
- res[:errors]
306
- end
307
-
308
- def define(**kwargs, &block)
309
- super
310
- ensure_defined
311
- # Assert that all necessary configs are present:
312
- validation_error = Validation.validate(self)
313
- validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
314
- rebuild_artifacts
315
-
316
- @definition_error = nil
317
- nil
318
- rescue StandardError => err
319
- if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
320
- raise
321
- else
322
- # Raise this error _later_ to avoid messing with Rails constant loading
323
- @definition_error = err
324
- end
325
- nil
326
- end
327
-
328
- # Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
329
- # @param instrumentation_type [Symbol]
330
- # @param instrumenter
331
- # @return [void]
332
- def instrument(instrumentation_type, instrumenter)
333
- @instrumenters[instrumentation_type] << instrumenter
334
- if instrumentation_type == :field
335
- rebuild_artifacts
336
- end
337
- end
338
-
339
- # @return [Array<GraphQL::BaseType>] The root types of this schema
340
- def root_types
341
- @root_types ||= begin
342
- rebuild_artifacts
343
- @root_types
344
- end
345
- end
346
-
347
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
348
- # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
349
- def types
350
- @types ||= begin
351
- rebuild_artifacts
352
- @types
353
- end
354
- end
355
-
356
- def get_type(type_name)
357
- @types[type_name]
358
- end
359
-
360
- # @api private
361
- def introspection_system
362
- @introspection_system ||= begin
363
- rebuild_artifacts
364
- @introspection_system
365
- end
366
- end
367
-
368
- # Returns a list of Arguments and Fields referencing a certain type
369
- # @param type_name [String]
370
- # @return [Hash]
371
- def references_to(type_name = nil)
372
- rebuild_artifacts unless defined?(@type_reference_map)
373
- if type_name
374
- @type_reference_map.fetch(type_name, [])
375
- else
376
- @type_reference_map
377
- end
378
- end
379
-
380
- # Returns a list of Union types in which a type is a member
381
- # @param type [GraphQL::ObjectType]
382
- # @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
383
- def union_memberships(type)
384
- rebuild_artifacts unless defined?(@union_memberships)
385
- @union_memberships.fetch(type.name, [])
386
- end
387
-
388
- # Execute a query on itself. Raises an error if the schema definition is invalid.
389
- # @see {Query#initialize} for arguments.
390
- # @return [Hash] query result, ready to be serialized as JSON
391
- def execute(query_str = nil, **kwargs)
392
- if query_str
393
- kwargs[:query] = query_str
394
- end
395
- # Some of the query context _should_ be passed to the multiplex, too
396
- multiplex_context = if (ctx = kwargs[:context])
397
- {
398
- backtrace: ctx[:backtrace],
399
- tracers: ctx[:tracers],
400
- }
401
- else
402
- {}
403
- end
404
- # Since we're running one query, don't run a multiplex-level complexity analyzer
405
- all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
406
- all_results[0]
407
- end
408
-
409
- # Execute several queries on itself. Raises an error if the schema definition is invalid.
410
- # @example Run several queries at once
411
- # context = { ... }
412
- # queries = [
413
- # { query: params[:query_1], variables: params[:variables_1], context: context },
414
- # { query: params[:query_2], variables: params[:variables_2], context: context },
415
- # ]
416
- # results = MySchema.multiplex(queries)
417
- # render json: {
418
- # result_1: results[0],
419
- # result_2: results[1],
420
- # }
421
- #
422
- # @see {Query#initialize} for query keyword arguments
423
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
424
- # @param queries [Array<Hash>] Keyword arguments for each query
425
- # @param context [Hash] Multiplex-level context
426
- # @return [Array<Hash>] One result for each query in the input
427
- def multiplex(queries, **kwargs)
428
- with_definition_error_check {
429
- GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
430
- }
431
- end
432
-
433
- # Search for a schema member using a string path
434
- # @example Finding a Field
435
- # Schema.find("Ensemble.musicians")
436
- #
437
- # @see {GraphQL::Schema::Finder} for more examples
438
- # @param path [String] A dot-separated path to the member
439
- # @raise [Schema::Finder::MemberNotFoundError] if path could not be found
440
- # @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
441
- def find(path)
442
- rebuild_artifacts unless defined?(@finder)
443
- @find_cache[path] ||= @finder.find(path)
444
- end
445
-
446
- # Resolve field named `field_name` for type `parent_type`.
447
- # Handles dynamic fields `__typename`, `__type` and `__schema`, too
448
- # @param parent_type [String, GraphQL::BaseType]
449
- # @param field_name [String]
450
- # @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
451
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
452
- def get_field(parent_type, field_name)
453
- with_definition_error_check do
454
- parent_type_name = case parent_type
455
- when GraphQL::BaseType, Class, Module
456
- parent_type.graphql_name
457
- when String
458
- parent_type
459
- else
460
- raise "Unexpected parent_type: #{parent_type}"
461
- end
462
-
463
- defined_field = @instrumented_field_map[parent_type_name][field_name]
464
- if defined_field
465
- defined_field
466
- elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
467
- entry_point_field
468
- elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
469
- dynamic_field
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
+ )
470
122
  else
471
- nil
472
- end
473
- end
474
- end
475
-
476
- # Fields for this type, after instrumentation is applied
477
- # @return [Hash<String, GraphQL::Field>]
478
- def get_fields(type)
479
- @instrumented_field_map[type.graphql_name]
480
- end
481
-
482
- def type_from_ast(ast_node, context:)
483
- GraphQL::Schema::TypeExpression.build_type(self, ast_node)
484
- end
485
-
486
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
487
- # @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
488
- # @param context [GraphQL::Query::Context] The context for the current query
489
- # @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
490
- def possible_types(type_defn, context = GraphQL::Query::NullContext)
491
- @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
492
- @possible_types.possible_types(type_defn, context)
493
- end
494
-
495
- # @see [GraphQL::Schema::Warden] Resticted access to root types
496
- # @return [GraphQL::ObjectType, nil]
497
- def root_type_for_operation(operation)
498
- case operation
499
- when "query"
500
- query
501
- when "mutation"
502
- mutation
503
- when "subscription"
504
- subscription
505
- else
506
- raise ArgumentError, "unknown operation type: #{operation}"
507
- end
508
- end
509
-
510
- def execution_strategy_for_operation(operation)
511
- case operation
512
- when "query"
513
- query_execution_strategy
514
- when "mutation"
515
- mutation_execution_strategy
516
- when "subscription"
517
- subscription_execution_strategy
518
- else
519
- raise ArgumentError, "unknown operation type: #{operation}"
520
- end
521
- end
522
-
523
- # Determine the GraphQL type for a given object.
524
- # This is required for unions and interfaces (including Relay's `Node` interface)
525
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
526
- # @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
527
- # @param object [Any] An application object which GraphQL is currently resolving on
528
- # @param ctx [GraphQL::Query::Context] The context for the current query
529
- # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
530
- def resolve_type(type, object, ctx = :__undefined__)
531
- check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
532
- if @resolve_type_proc.nil?
533
- raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
123
+ GraphQL::Schema::BuildFromDefinition.from_definition(
124
+ self,
125
+ definition_or_path,
126
+ default_resolve: default_resolve,
127
+ parser: parser,
128
+ using: using,
129
+ )
534
130
  end
535
- @resolve_type_proc.call(ok_type, ok_object, ok_ctx)
536
131
  end
537
- end
538
132
 
539
- # This is a compatibility hack so that instance-level and class-level
540
- # methods can get correctness checks without calling one another
541
- # @api private
542
- def check_resolved_type(type, object, ctx = :__undefined__)
543
- if ctx == :__undefined__
544
- # Old method signature
545
- ctx = object
546
- object = type
547
- type = nil
133
+ def deprecated_graphql_definition
134
+ graphql_definition(silence_deprecation_warning: true)
548
135
  end
549
136
 
550
- if object.is_a?(GraphQL::Schema::Object)
551
- object = object.object
137
+ # @return [GraphQL::Subscriptions]
138
+ def subscriptions(inherited: true)
139
+ defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
552
140
  end
553
141
 
554
- if type.respond_to?(:graphql_definition)
555
- type = type.graphql_definition
142
+ def subscriptions=(new_implementation)
143
+ @subscriptions = new_implementation
556
144
  end
557
145
 
558
- # Prefer a type-local function; fall back to the schema-level function
559
- type_proc = type && type.resolve_type_proc
560
- type_result = if type_proc
561
- type_proc.call(object, ctx)
562
- else
563
- yield(type, object, ctx)
146
+ def trace_class(new_class = nil)
147
+ if new_class
148
+ trace_mode(:default, new_class)
149
+ backtrace_class = Class.new(new_class)
150
+ backtrace_class.include(GraphQL::Backtrace::Trace)
151
+ trace_mode(:default_backtrace, backtrace_class)
152
+ end
153
+ trace_class_for(:default)
564
154
  end
565
155
 
566
- if type_result.nil?
567
- nil
568
- else
569
- after_lazy(type_result) do |resolved_type_result|
570
- if resolved_type_result.respond_to?(:graphql_definition)
571
- resolved_type_result = resolved_type_result.graphql_definition
572
- end
573
- if !resolved_type_result.is_a?(GraphQL::BaseType)
574
- type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
575
- raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
156
+ # @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.
157
+ def trace_class_for(mode)
158
+ @trace_modes ||= {}
159
+ @trace_modes[mode] ||= begin
160
+ base_class = if superclass.respond_to?(:trace_class_for)
161
+ superclass.trace_class_for(mode)
162
+ elsif mode == :default_backtrace
163
+ GraphQL::Backtrace::DefaultBacktraceTrace
576
164
  else
577
- resolved_type_result
165
+ GraphQL::Tracing::Trace
578
166
  end
167
+ Class.new(base_class)
579
168
  end
580
169
  end
581
- end
582
-
583
- def resolve_type=(new_resolve_type_proc)
584
- callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
585
- @resolve_type_proc = callable
586
- end
587
-
588
- # Fetch an application object by its unique id
589
- # @param id [String] A unique identifier, provided previously by this GraphQL schema
590
- # @param ctx [GraphQL::Query::Context] The context for the current query
591
- # @return [Any] The application object identified by `id`
592
- def object_from_id(id, ctx)
593
- if @object_from_id_proc.nil?
594
- raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
595
- else
596
- @object_from_id_proc.call(id, ctx)
597
- end
598
- end
599
-
600
- # @param new_proc [#call] A new callable for fetching objects by ID
601
- def object_from_id=(new_proc)
602
- @object_from_id_proc = new_proc
603
- end
604
-
605
- # When we encounter a type error during query execution, we call this hook.
606
- #
607
- # You can use this hook to write a log entry,
608
- # add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
609
- # or raise an exception and halt query execution.
610
- #
611
- # @example A `nil` is encountered by a non-null field
612
- # type_error ->(err, query_ctx) {
613
- # err.is_a?(GraphQL::InvalidNullError) # => true
614
- # }
615
- #
616
- # @example An object doesn't resolve to one of a {UnionType}'s members
617
- # type_error ->(err, query_ctx) {
618
- # err.is_a?(GraphQL::UnresolvedTypeError) # => true
619
- # }
620
- #
621
- # @see {DefaultTypeError} is the default behavior.
622
- # @param err [GraphQL::TypeError] The error encountered during execution
623
- # @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
624
- # @return void
625
- def type_error(err, ctx)
626
- @type_error_proc.call(err, ctx)
627
- end
628
-
629
- # @param new_proc [#call] A new callable for handling type errors during execution
630
- def type_error=(new_proc)
631
- @type_error_proc = new_proc
632
- end
633
-
634
- # Can't delegate to `class`
635
- alias :_schema_class :class
636
- def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
637
- def_delegators :_schema_class, :directive
638
- def_delegators :_schema_class, :error_handler
639
-
640
-
641
- # Given this schema member, find the class-based definition object
642
- # whose `method_name` should be treated as an application hook
643
- # @see {.visible?}
644
- # @see {.accessible?}
645
- def call_on_type_class(member, method_name, context, default:)
646
- member = if member.respond_to?(:type_class)
647
- member.type_class
648
- else
649
- member
650
- end
651
-
652
- if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
653
- member = t
654
- end
655
-
656
- if member.respond_to?(method_name)
657
- member.public_send(method_name, context)
658
- else
659
- default
660
- end
661
- end
662
-
663
- def visible?(member, context)
664
- call_on_type_class(member, :visible?, context, default: true)
665
- end
666
-
667
- def accessible?(member, context)
668
- call_on_type_class(member, :accessible?, context, default: true)
669
- end
670
-
671
- # A function to call when {#execute} receives an invalid query string
672
- #
673
- # @see {DefaultParseError} is the default behavior.
674
- # @param err [GraphQL::ParseError] The error encountered during parsing
675
- # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
676
- # @return void
677
- def parse_error(err, ctx)
678
- @parse_error_proc.call(err, ctx)
679
- end
680
-
681
- # @param new_proc [#call] A new callable for handling parse errors during execution
682
- def parse_error=(new_proc)
683
- @parse_error_proc = new_proc
684
- end
685
170
 
686
- # Get a unique identifier from this object
687
- # @param object [Any] An application object
688
- # @param type [GraphQL::BaseType] The current type definition
689
- # @param ctx [GraphQL::Query::Context] the context for the current query
690
- # @return [String] a unique identifier for `object` which clients can use to refetch it
691
- def id_from_object(object, type, ctx)
692
- if @id_from_object_proc.nil?
693
- raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
694
- else
695
- @id_from_object_proc.call(object, type, ctx)
171
+ # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
172
+ # `:default` is used when no `trace_mode: ...` is requested.
173
+ # @param mode_name [Symbol]
174
+ # @param trace_class [Class] subclass of GraphQL::Tracing::Trace
175
+ # @return void
176
+ def trace_mode(mode_name, trace_class)
177
+ @trace_modes ||= {}
178
+ @trace_modes[mode_name] = trace_class
179
+ nil
696
180
  end
697
- end
698
-
699
- # @param new_proc [#call] A new callable for generating unique IDs
700
- def id_from_object=(new_proc)
701
- @id_from_object_proc = new_proc
702
- end
703
-
704
- # Create schema with the result of an introspection query.
705
- # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
706
- # @return [GraphQL::Schema] the schema described by `input`
707
- def self.from_introspection(introspection_result)
708
- GraphQL::Schema::Loader.load(introspection_result)
709
- end
710
-
711
- # Create schema from an IDL schema or file containing an IDL definition.
712
- # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
713
- # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
714
- # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
715
- # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
716
- # @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
717
- # @return [Class] the schema described by `document`
718
- def self.from_definition(definition_or_path, default_resolve: BuildFromDefinition::DefaultResolve, interpreter: true, parser: BuildFromDefinition::DefaultParser, using: {})
719
- # If the file ends in `.graphql`, treat it like a filepath
720
- definition = if definition_or_path.end_with?(".graphql")
721
- File.read(definition_or_path)
722
- else
723
- definition_or_path
724
- end
725
- GraphQL::Schema::BuildFromDefinition.from_definition(definition, default_resolve: default_resolve, parser: parser, using: using, interpreter: interpreter)
726
- end
727
-
728
- # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
729
- class InvalidDocumentError < Error; end;
730
-
731
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
732
- def lazy_method_name(obj)
733
- @lazy_methods.get(obj)
734
- end
735
181
 
736
- # @return [Boolean] True if this object should be lazily resolved
737
- def lazy?(obj)
738
- !!lazy_method_name(obj)
739
- end
740
-
741
- # Return the GraphQL IDL for the schema
742
- # @param context [Hash]
743
- # @param only [<#call(member, ctx)>]
744
- # @param except [<#call(member, ctx)>]
745
- # @return [String]
746
- def to_definition(only: nil, except: nil, context: {})
747
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
748
- end
749
-
750
- # Return the GraphQL::Language::Document IDL AST for the schema
751
- # @param context [Hash]
752
- # @param only [<#call(member, ctx)>]
753
- # @param except [<#call(member, ctx)>]
754
- # @return [GraphQL::Language::Document]
755
- def to_document(only: nil, except: nil, context: {})
756
- GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
757
- end
758
-
759
- # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
760
- # @param context [Hash]
761
- # @param only [<#call(member, ctx)>]
762
- # @param except [<#call(member, ctx)>]
763
- # @return [Hash] GraphQL result
764
- def as_json(only: nil, except: nil, context: {})
765
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
766
- end
767
-
768
- # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
769
- # @see {#as_json}
770
- # @return [String]
771
- def to_json(*args)
772
- JSON.pretty_generate(as_json(*args))
773
- end
774
-
775
- def new_connections?
776
- !!connections
777
- end
778
-
779
- attr_accessor :connections
780
-
781
- class << self
782
- extend Forwardable
783
- # For compatibility, these methods all:
784
- # - Cause the Schema instance to be created, if it hasn't been created yet
785
- # - Delegate to that instance
786
- # Eventually, the methods will be moved into this class, removing the need for the singleton.
787
- def_delegators :graphql_definition,
788
- # Execution
789
- :execution_strategy_for_operation,
790
- :validate, :multiplex_analyzers,
791
- # Configuration
792
- :metadata, :redefine,
793
- :id_from_object_proc, :object_from_id_proc,
794
- :id_from_object=, :object_from_id=,
795
- :remove_handler
796
-
797
- # @return [GraphQL::Subscriptions]
798
- attr_accessor :subscriptions
799
182
 
800
183
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
801
184
  # @see {#as_json}
802
185
  # @return [String]
803
- def to_json(*args)
804
- JSON.pretty_generate(as_json(*args))
186
+ def to_json(**args)
187
+ JSON.pretty_generate(as_json(**args))
805
188
  end
806
189
 
807
190
  # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
808
191
  # @param context [Hash]
809
192
  # @param only [<#call(member, ctx)>]
810
193
  # @param except [<#call(member, ctx)>]
194
+ # @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
195
+ # @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
196
+ # @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
197
+ # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
198
+ # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
811
199
  # @return [Hash] GraphQL result
812
- def as_json(only: nil, except: nil, context: {})
813
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
200
+ def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
201
+ introspection_query = Introspection.query(
202
+ include_deprecated_args: include_deprecated_args,
203
+ include_schema_description: include_schema_description,
204
+ include_is_repeatable: include_is_repeatable,
205
+ include_is_one_of: include_is_one_of,
206
+ include_specified_by_url: include_specified_by_url,
207
+ )
208
+
209
+ execute(introspection_query, only: only, except: except, context: context).to_h
814
210
  end
815
211
 
816
212
  # Return the GraphQL IDL for the schema
@@ -828,6 +224,17 @@ module GraphQL
828
224
  GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
829
225
  end
830
226
 
227
+ # @return [String, nil]
228
+ def description(new_description = nil)
229
+ if new_description
230
+ @description = new_description
231
+ elsif defined?(@description)
232
+ @description
233
+ else
234
+ find_inherited_value(:description, nil)
235
+ end
236
+ end
237
+
831
238
  def find(path)
832
239
  if !@finder
833
240
  @find_cache = {}
@@ -836,12 +243,8 @@ module GraphQL
836
243
  @find_cache[path] ||= @finder.find(path)
837
244
  end
838
245
 
839
- def graphql_definition
840
- @graphql_definition ||= to_graphql
841
- end
842
-
843
246
  def default_filter
844
- GraphQL::Filter.new(except: default_mask)
247
+ GraphQL::Filter.new(except: default_mask, silence_deprecation_warning: true)
845
248
  end
846
249
 
847
250
  def default_mask(new_mask = nil)
@@ -869,81 +272,85 @@ module GraphQL
869
272
  find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
870
273
  end
871
274
 
872
- def to_graphql
873
- schema_defn = self.new
874
- schema_defn.raise_definition_error = true
875
- schema_defn.query = query && query.graphql_definition
876
- schema_defn.mutation = mutation && mutation.graphql_definition
877
- schema_defn.subscription = subscription && subscription.graphql_definition
878
- schema_defn.max_complexity = max_complexity
879
- schema_defn.error_bubbling = error_bubbling
880
- schema_defn.max_depth = max_depth
881
- schema_defn.default_max_page_size = default_max_page_size
882
- schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
883
- schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
884
- schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
885
- schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
886
-
887
- prepped_dirs = {}
888
- directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
889
- schema_defn.directives = prepped_dirs
890
- schema_defn.introspection_namespace = introspection
891
- schema_defn.resolve_type = method(:resolve_type)
892
- schema_defn.object_from_id = method(:object_from_id)
893
- schema_defn.id_from_object = method(:id_from_object)
894
- schema_defn.type_error = method(:type_error)
895
- schema_defn.context_class = context_class
896
- schema_defn.cursor_encoder = cursor_encoder
897
- schema_defn.tracers.concat(tracers)
898
- schema_defn.query_analyzers.concat(query_analyzers)
899
-
900
- schema_defn.middleware.concat(all_middleware)
901
- schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
902
- schema_defn.query_execution_strategy = query_execution_strategy
903
- schema_defn.mutation_execution_strategy = mutation_execution_strategy
904
- schema_defn.subscription_execution_strategy = subscription_execution_strategy
905
- schema_defn.default_mask = default_mask
906
- instrumenters.each do |step, insts|
907
- insts.each do |inst|
908
- schema_defn.instrumenters[step] << inst
909
- end
910
- end
911
-
912
- lazy_methods.each do |lazy_class, value_method|
913
- schema_defn.lazy_methods.set(lazy_class, value_method)
914
- end
915
-
916
- rescues.each do |err_class, handler|
917
- schema_defn.rescue_from(err_class, &handler)
918
- end
919
-
920
- schema_defn.subscriptions ||= self.subscriptions
921
-
922
- if !schema_defn.interpreter?
923
- schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
924
- end
925
- schema_defn.send(:rebuild_artifacts)
926
-
927
- schema_defn
928
- end
929
-
930
275
  # Build a map of `{ name => type }` and return it
931
276
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
932
277
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
933
- def types
934
- non_introspection_types.merge(introspection_system.types)
278
+ def types(context = GraphQL::Query::NullContext)
279
+ all_types = non_introspection_types.merge(introspection_system.types)
280
+ visible_types = {}
281
+ all_types.each do |k, v|
282
+ visible_types[k] =if v.is_a?(Array)
283
+ visible_t = nil
284
+ v.each do |t|
285
+ if t.visible?(context)
286
+ if visible_t.nil?
287
+ visible_t = t
288
+ else
289
+ raise DuplicateNamesError.new(
290
+ duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
291
+ )
292
+ end
293
+ end
294
+ end
295
+ visible_t
296
+ else
297
+ v
298
+ end
299
+ end
300
+ visible_types
935
301
  end
936
302
 
937
303
  # @param type_name [String]
938
304
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
939
- def get_type(type_name)
940
- own_types[type_name] ||
941
- introspection_system.types[type_name] ||
942
- find_inherited_value(:types, EMPTY_HASH)[type_name]
305
+ def get_type(type_name, context = GraphQL::Query::NullContext)
306
+ local_entry = own_types[type_name]
307
+ type_defn = case local_entry
308
+ when nil
309
+ nil
310
+ when Array
311
+ visible_t = nil
312
+ warden = Warden.from_context(context)
313
+ local_entry.each do |t|
314
+ if warden.visible_type?(t, context)
315
+ if visible_t.nil?
316
+ visible_t = t
317
+ else
318
+ raise DuplicateNamesError.new(
319
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
320
+ )
321
+ end
322
+ end
323
+ end
324
+ visible_t
325
+ when Module
326
+ local_entry
327
+ else
328
+ raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
329
+ end
330
+
331
+ type_defn ||
332
+ introspection_system.types[type_name] || # todo context-specific introspection?
333
+ (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
943
334
  end
944
335
 
336
+ # @api private
337
+ attr_writer :connections
338
+
945
339
  # @return [GraphQL::Pagination::Connections] if installed
946
- attr_accessor :connections
340
+ def connections
341
+ if defined?(@connections)
342
+ @connections
343
+ else
344
+ inherited_connections = find_inherited_value(:connections, nil)
345
+ # This schema is part of an inheritance chain which is using new connections,
346
+ # make a new instance, so we don't pollute the upstream one.
347
+ if inherited_connections
348
+ @connections = Pagination::Connections.new(schema: self)
349
+ else
350
+ nil
351
+ end
352
+ end
353
+ end
947
354
 
948
355
  def new_connections?
949
356
  !!connections
@@ -983,6 +390,7 @@ module GraphQL
983
390
  raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
984
391
  else
985
392
  @subscription_object = new_subscription_object
393
+ add_subscription_extension_if_necessary
986
394
  add_type_and_traverse(new_subscription_object, root: true)
987
395
  nil
988
396
  end
@@ -991,7 +399,7 @@ module GraphQL
991
399
  end
992
400
  end
993
401
 
994
- # @see [GraphQL::Schema::Warden] Resticted access to root types
402
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
995
403
  # @return [GraphQL::ObjectType, nil]
996
404
  def root_type_for_operation(operation)
997
405
  case operation
@@ -1019,7 +427,15 @@ module GraphQL
1019
427
  if type.kind.union?
1020
428
  type.possible_types(context: context)
1021
429
  else
1022
- own_possible_types[type.graphql_name] ||
430
+ stored_possible_types = own_possible_types[type.graphql_name]
431
+ visible_possible_types = if stored_possible_types && type.kind.interface?
432
+ stored_possible_types.select do |possible_type|
433
+ possible_type.interfaces(context).include?(type)
434
+ end
435
+ else
436
+ stored_possible_types
437
+ end
438
+ visible_possible_types ||
1023
439
  introspection_system.possible_types[type.graphql_name] ||
1024
440
  (
1025
441
  superclass.respond_to?(:possible_types) ?
@@ -1049,6 +465,14 @@ module GraphQL
1049
465
  end
1050
466
  end
1051
467
 
468
+ # @api private
469
+ # @see GraphQL::Dataloader
470
+ def dataloader_class
471
+ @dataloader_class || GraphQL::Dataloader::NullDataloader
472
+ end
473
+
474
+ attr_writer :dataloader_class
475
+
1052
476
  def references_to(to_type = nil, from: nil)
1053
477
  @own_references_to ||= Hash.new { |h, k| h[k] = [] }
1054
478
  if to_type
@@ -1081,19 +505,19 @@ module GraphQL
1081
505
  GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
1082
506
  end
1083
507
 
1084
- def get_field(type_or_name, field_name)
508
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
1085
509
  parent_type = case type_or_name
1086
510
  when LateBoundType
1087
- get_type(type_or_name.name)
511
+ get_type(type_or_name.name, context)
1088
512
  when String
1089
- get_type(type_or_name)
513
+ get_type(type_or_name, context)
1090
514
  when Module
1091
515
  type_or_name
1092
516
  else
1093
- raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
517
+ raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
1094
518
  end
1095
519
 
1096
- if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
520
+ if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
1097
521
  field
1098
522
  elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
1099
523
  entry_point_field
@@ -1104,8 +528,8 @@ module GraphQL
1104
528
  end
1105
529
  end
1106
530
 
1107
- def get_fields(type)
1108
- type.fields
531
+ def get_fields(type, context = GraphQL::Query::NullContext)
532
+ type.fields(context)
1109
533
  end
1110
534
 
1111
535
  def introspection(new_introspection_namespace = nil)
@@ -1141,6 +565,14 @@ module GraphQL
1141
565
  end
1142
566
  end
1143
567
 
568
+ def default_page_size(new_default_page_size = nil)
569
+ if new_default_page_size
570
+ @default_page_size = new_default_page_size
571
+ else
572
+ @default_page_size || find_inherited_value(:default_page_size)
573
+ end
574
+ end
575
+
1144
576
  def query_execution_strategy(new_query_execution_strategy = nil)
1145
577
  if new_query_execution_strategy
1146
578
  @query_execution_strategy = new_query_execution_strategy
@@ -1165,6 +597,47 @@ module GraphQL
1165
597
  end
1166
598
  end
1167
599
 
600
+ attr_writer :validate_timeout
601
+
602
+ def validate_timeout(new_validate_timeout = nil)
603
+ if new_validate_timeout
604
+ @validate_timeout = new_validate_timeout
605
+ elsif defined?(@validate_timeout)
606
+ @validate_timeout
607
+ else
608
+ find_inherited_value(:validate_timeout)
609
+ end
610
+ end
611
+
612
+ # Validate a query string according to this schema.
613
+ # @param string_or_document [String, GraphQL::Language::Nodes::Document]
614
+ # @return [Array<GraphQL::StaticValidation::Error >]
615
+ def validate(string_or_document, rules: nil, context: nil)
616
+ doc = if string_or_document.is_a?(String)
617
+ GraphQL.parse(string_or_document)
618
+ else
619
+ string_or_document
620
+ end
621
+ query = GraphQL::Query.new(self, document: doc, context: context)
622
+ validator_opts = { schema: self }
623
+ rules && (validator_opts[:rules] = rules)
624
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
625
+ res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
626
+ res[:errors]
627
+ end
628
+
629
+ attr_writer :validate_max_errors
630
+
631
+ def validate_max_errors(new_validate_max_errors = nil)
632
+ if new_validate_max_errors
633
+ @validate_max_errors = new_validate_max_errors
634
+ elsif defined?(@validate_max_errors)
635
+ @validate_max_errors
636
+ else
637
+ find_inherited_value(:validate_max_errors)
638
+ end
639
+ end
640
+
1168
641
  attr_writer :max_complexity
1169
642
 
1170
643
  def max_complexity(max_complexity = nil)
@@ -1180,19 +653,15 @@ module GraphQL
1180
653
  attr_writer :analysis_engine
1181
654
 
1182
655
  def analysis_engine
1183
- @analysis_engine || find_inherited_value(:analysis_engine, GraphQL::Analysis)
656
+ @analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
1184
657
  end
1185
658
 
1186
659
  def using_ast_analysis?
1187
- analysis_engine == GraphQL::Analysis::AST
660
+ true
1188
661
  end
1189
662
 
1190
663
  def interpreter?
1191
- if defined?(@interpreter)
1192
- @interpreter
1193
- else
1194
- find_inherited_value(:interpreter?, false)
1195
- end
664
+ true
1196
665
  end
1197
666
 
1198
667
  attr_writer :interpreter
@@ -1265,7 +734,6 @@ module GraphQL
1265
734
  if new_orphan_types.any?
1266
735
  new_orphan_types = new_orphan_types.flatten
1267
736
  add_type_and_traverse(new_orphan_types, root: false)
1268
- @orphan_types = new_orphan_types
1269
737
  own_orphan_types.concat(new_orphan_types.flatten)
1270
738
  end
1271
739
 
@@ -1276,7 +744,15 @@ module GraphQL
1276
744
  if superclass <= GraphQL::Schema
1277
745
  superclass.default_execution_strategy
1278
746
  else
1279
- @default_execution_strategy ||= GraphQL::Execution::Execute
747
+ @default_execution_strategy ||= GraphQL::Execution::Interpreter
748
+ end
749
+ end
750
+
751
+ def default_analysis_engine
752
+ if superclass <= GraphQL::Schema
753
+ superclass.default_analysis_engine
754
+ else
755
+ @default_analysis_engine ||= GraphQL::Analysis::AST
1280
756
  end
1281
757
  end
1282
758
 
@@ -1290,22 +766,63 @@ module GraphQL
1290
766
 
1291
767
  def rescue_from(*err_classes, &handler_block)
1292
768
  err_classes.each do |err_class|
1293
- own_rescues[err_class] = handler_block
769
+ Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
770
+ end
771
+ end
772
+
773
+ NEW_HANDLER_HASH = ->(h, k) {
774
+ h[k] = {
775
+ class: k,
776
+ handler: nil,
777
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
778
+ }
779
+ }
780
+
781
+ def error_handlers
782
+ @error_handlers ||= {
783
+ class: nil,
784
+ handler: nil,
785
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
786
+ }
787
+ end
788
+
789
+ # @api private
790
+ def handle_or_reraise(context, err)
791
+ handler = Execution::Errors.find_handler_for(self, err.class)
792
+ if handler
793
+ obj = context[:current_object]
794
+ args = context[:current_arguments]
795
+ args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
796
+ field = context[:current_field]
797
+ if obj.is_a?(GraphQL::Schema::Object)
798
+ obj = obj.object
799
+ end
800
+ handler[:handler].call(err, obj, args, context, field)
801
+ else
802
+ raise err
1294
803
  end
1295
804
  end
1296
805
 
1297
806
  # rubocop:disable Lint/DuplicateMethods
1298
807
  module ResolveTypeWithType
1299
808
  def resolve_type(type, obj, ctx)
1300
- first_resolved_type = if type.is_a?(Module) && type.respond_to?(:resolve_type)
809
+ maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1301
810
  type.resolve_type(obj, ctx)
1302
811
  else
1303
812
  super
1304
813
  end
1305
814
 
1306
- after_lazy(first_resolved_type) do |resolved_type|
1307
- if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
1308
- resolved_type
815
+ after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
816
+ if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
817
+ resolved_type = resolve_type_result[0]
818
+ resolved_value = resolve_type_result[1]
819
+ else
820
+ resolved_type = resolve_type_result
821
+ resolved_value = obj
822
+ end
823
+
824
+ if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
825
+ [resolved_type, resolved_value]
1309
826
  else
1310
827
  raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
1311
828
  end
@@ -1330,10 +847,6 @@ module GraphQL
1330
847
  super
1331
848
  end
1332
849
 
1333
- def rescues
1334
- find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
1335
- end
1336
-
1337
850
  def object_from_id(node_id, ctx)
1338
851
  raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1339
852
  end
@@ -1343,23 +856,16 @@ module GraphQL
1343
856
  end
1344
857
 
1345
858
  def visible?(member, ctx)
1346
- member.type_class.visible?(ctx)
859
+ member.visible?(ctx)
1347
860
  end
1348
861
 
1349
- def accessible?(member, ctx)
1350
- member.type_class.accessible?(ctx)
862
+ def schema_directive(dir_class, **options)
863
+ @own_schema_directives ||= []
864
+ Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
1351
865
  end
1352
866
 
1353
- # This hook is called when a client tries to access one or more
1354
- # fields that fail the `accessible?` check.
1355
- #
1356
- # By default, an error is added to the response. Override this hook to
1357
- # track metrics or return a different error to the client.
1358
- #
1359
- # @param error [InaccessibleFieldsError] The analysis error for this check
1360
- # @return [AnalysisError, nil] Return an error to skip the query
1361
- def inaccessible_fields(error)
1362
- error
867
+ def schema_directives
868
+ Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
1363
869
  end
1364
870
 
1365
871
  # This hook is called when an object fails an `authorized?` check.
@@ -1397,45 +903,40 @@ module GraphQL
1397
903
  unauthorized_object(unauthorized_error)
1398
904
  end
1399
905
 
1400
- def type_error(type_err, ctx)
1401
- DefaultTypeError.call(type_err, ctx)
906
+ def type_error(type_error, ctx)
907
+ case type_error
908
+ when GraphQL::InvalidNullError
909
+ ctx.errors << type_error
910
+ when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
911
+ raise type_error
912
+ when GraphQL::IntegerDecodingError
913
+ nil
914
+ end
1402
915
  end
1403
916
 
1404
917
  # A function to call when {#execute} receives an invalid query string
1405
918
  #
1406
919
  # The default is to add the error to `context.errors`
1407
- # @param err [GraphQL::ParseError] The error encountered during parsing
920
+ # @param parse_err [GraphQL::ParseError] The error encountered during parsing
1408
921
  # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
1409
922
  # @return void
1410
923
  def parse_error(parse_err, ctx)
1411
924
  ctx.errors.push(parse_err)
1412
925
  end
1413
- attr_writer :error_handler
1414
-
1415
- # @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
1416
- def error_handler
1417
- @error_handler ||= GraphQL::Execution::Errors::NullErrorHandler
1418
- end
1419
926
 
1420
927
  def lazy_resolve(lazy_class, value_method)
1421
928
  lazy_methods.set(lazy_class, value_method)
1422
929
  end
1423
930
 
1424
931
  def instrument(instrument_step, instrumenter, options = {})
1425
- step = if instrument_step == :field && options[:after_built_ins]
1426
- :field_after_built_ins
1427
- else
1428
- instrument_step
1429
- end
1430
-
1431
- own_instrumenters[step] << instrumenter
932
+ own_instrumenters[instrument_step] << instrumenter
1432
933
  end
1433
934
 
1434
935
  # Add several directives at once
1435
936
  # @param new_directives [Class]
1436
- def directives(new_directives = nil)
1437
- if new_directives
1438
- new_directives.each { |d| directive(d) }
937
+ def directives(*new_directives)
938
+ if new_directives.any?
939
+ new_directives.flatten.each { |d| directive(d) }
1439
940
  end
1440
941
 
1441
942
  find_inherited_value(:directives, default_directives).merge(own_directives)
@@ -1443,20 +944,27 @@ module GraphQL
1443
944
 
1444
945
  # Attach a single directive to this schema
1445
946
  # @param new_directive [Class]
947
+ # @return void
1446
948
  def directive(new_directive)
1447
949
  add_type_and_traverse(new_directive, root: false)
1448
- own_directives[new_directive.graphql_name] = new_directive
1449
950
  end
1450
951
 
1451
952
  def default_directives
1452
- {
953
+ @default_directives ||= {
1453
954
  "include" => GraphQL::Schema::Directive::Include,
1454
955
  "skip" => GraphQL::Schema::Directive::Skip,
1455
956
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
1456
- }
957
+ "oneOf" => GraphQL::Schema::Directive::OneOf,
958
+ }.freeze
1457
959
  end
1458
960
 
1459
961
  def tracer(new_tracer)
962
+ if defined?(@trace_modes) && !(trace_class_for(:default) < GraphQL::Tracing::LegacyTrace)
963
+ raise ArgumentError, "Can't add tracer after configuring a `trace_class`, use GraphQL::Tracing::LegacyTrace to merge legacy tracers into a trace class instead."
964
+ else
965
+ trace_mode(:default, Class.new(GraphQL::Tracing::LegacyTrace))
966
+ end
967
+
1460
968
  own_tracers << new_tracer
1461
969
  end
1462
970
 
@@ -1464,24 +972,40 @@ module GraphQL
1464
972
  find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1465
973
  end
1466
974
 
1467
- def query_analyzer(new_analyzer)
1468
- if new_analyzer == GraphQL::Authorization::Analyzer
1469
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1470
- end
1471
- own_query_analyzers << new_analyzer
975
+ # Mix `trace_mod` into this schema's `Trace` class so that its methods
976
+ # will be called at runtime.
977
+ #
978
+ # @param trace_mod [Module] A module that implements tracing methods
979
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
980
+ # @return [void]
981
+ def trace_with(trace_mod, **options)
982
+ trace_options.merge!(options)
983
+ trace_class.include(trace_mod)
1472
984
  end
1473
985
 
1474
- def query_analyzers
1475
- find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
986
+ def trace_options
987
+ @trace_options ||= superclass.respond_to?(:trace_options) ? superclass.trace_options.dup : {}
1476
988
  end
1477
989
 
1478
- def middleware(new_middleware = nil)
1479
- if new_middleware
1480
- own_middleware << new_middleware
990
+ def new_trace(**options)
991
+ if defined?(@trace_options)
992
+ options = trace_options.merge(options)
993
+ end
994
+ trace_mode = if (target = options[:query] || options[:multiplex]) && target.context[:backtrace]
995
+ :default_backtrace
1481
996
  else
1482
- # TODO make sure this is cached when running a query
1483
- MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
997
+ :default
1484
998
  end
999
+ trace = trace_class_for(trace_mode).new(**options)
1000
+ trace
1001
+ end
1002
+
1003
+ def query_analyzer(new_analyzer)
1004
+ own_query_analyzers << new_analyzer
1005
+ end
1006
+
1007
+ def query_analyzers
1008
+ find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1485
1009
  end
1486
1010
 
1487
1011
  def multiplex_analyzer(new_analyzer)
@@ -1492,6 +1016,14 @@ module GraphQL
1492
1016
  find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1493
1017
  end
1494
1018
 
1019
+ def sanitized_printer(new_sanitized_printer = nil)
1020
+ if new_sanitized_printer
1021
+ @own_sanitized_printer = new_sanitized_printer
1022
+ else
1023
+ @own_sanitized_printer || GraphQL::Language::SanitizedPrinter
1024
+ end
1025
+ end
1026
+
1495
1027
  # Execute a query on itself.
1496
1028
  # @see {Query#initialize} for arguments.
1497
1029
  # @return [Hash] query result, ready to be serialized as JSON
@@ -1504,6 +1036,7 @@ module GraphQL
1504
1036
  {
1505
1037
  backtrace: ctx[:backtrace],
1506
1038
  tracers: ctx[:tracers],
1039
+ dataloader: ctx[:dataloader],
1507
1040
  }
1508
1041
  else
1509
1042
  {}
@@ -1528,17 +1061,12 @@ module GraphQL
1528
1061
  # }
1529
1062
  #
1530
1063
  # @see {Query#initialize} for query keyword arguments
1531
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
1064
+ # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
1532
1065
  # @param queries [Array<Hash>] Keyword arguments for each query
1533
1066
  # @param context [Hash] Multiplex-level context
1534
1067
  # @return [Array<Hash>] One result for each query in the input
1535
1068
  def multiplex(queries, **kwargs)
1536
- schema = if interpreter?
1537
- self
1538
- else
1539
- graphql_definition
1540
- end
1541
- GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
1069
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1542
1070
  end
1543
1071
 
1544
1072
  def instrumenters
@@ -1548,18 +1076,32 @@ module GraphQL
1548
1076
  end
1549
1077
  end
1550
1078
 
1079
+ # @api private
1080
+ def add_subscription_extension_if_necessary
1081
+ if !defined?(@subscription_extension_added) && subscription && self.subscriptions
1082
+ @subscription_extension_added = true
1083
+ subscription.all_field_definitions.each do |field|
1084
+ if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
1085
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1086
+ end
1087
+ end
1088
+ end
1089
+ end
1090
+
1091
+ def query_stack_error(query, err)
1092
+ query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1093
+ end
1094
+
1551
1095
  # Call the given block at the right time, either:
1552
1096
  # - Right away, if `value` is not registered with `lazy_resolve`
1553
1097
  # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1554
1098
  # @api private
1555
- def after_lazy(value)
1099
+ def after_lazy(value, &block)
1556
1100
  if lazy?(value)
1557
1101
  GraphQL::Execution::Lazy.new do
1558
1102
  result = sync_lazy(value)
1559
1103
  # The returned result might also be lazy, so check it, too
1560
- after_lazy(result) do |final_result|
1561
- yield(final_result) if block_given?
1562
- end
1104
+ after_lazy(result, &block)
1563
1105
  end
1564
1106
  else
1565
1107
  yield(value) if block_given?
@@ -1568,8 +1110,8 @@ module GraphQL
1568
1110
 
1569
1111
  # Override this method to handle lazy objects in a custom way.
1570
1112
  # @param value [Object] an instance of a class registered with {.lazy_resolve}
1571
- # @param ctx [GraphQL::Query::Context] the context for this query
1572
1113
  # @return [Object] A GraphQL-ready (non-lazy) object
1114
+ # @api private
1573
1115
  def sync_lazy(value)
1574
1116
  lazy_method = lazy_method_name(value)
1575
1117
  if lazy_method
@@ -1580,7 +1122,7 @@ module GraphQL
1580
1122
  end
1581
1123
  end
1582
1124
 
1583
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
1125
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
1584
1126
  def lazy_method_name(obj)
1585
1127
  lazy_methods.get(obj)
1586
1128
  end
@@ -1590,8 +1132,75 @@ module GraphQL
1590
1132
  !!lazy_method_name(obj)
1591
1133
  end
1592
1134
 
1135
+ # Return a lazy if any of `maybe_lazies` are lazy,
1136
+ # otherwise, call the block eagerly and return the result.
1137
+ # @param maybe_lazies [Array]
1138
+ # @api private
1139
+ def after_any_lazies(maybe_lazies)
1140
+ if maybe_lazies.any? { |l| lazy?(l) }
1141
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
1142
+ yield result
1143
+ end
1144
+ else
1145
+ yield maybe_lazies
1146
+ end
1147
+ end
1148
+
1593
1149
  private
1594
1150
 
1151
+ # @param t [Module, Array<Module>]
1152
+ # @return [void]
1153
+ def add_type_and_traverse(t, root:)
1154
+ if root
1155
+ @root_types ||= []
1156
+ @root_types << t
1157
+ end
1158
+ new_types = Array(t)
1159
+ addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1160
+ addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
1161
+ if (prev_entry = own_types[name])
1162
+ prev_entries = case prev_entry
1163
+ when Array
1164
+ prev_entry
1165
+ when Module
1166
+ own_types[name] = [prev_entry]
1167
+ else
1168
+ raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
1169
+ end
1170
+
1171
+ case types_entry
1172
+ when Array
1173
+ prev_entries.concat(types_entry)
1174
+ prev_entries.uniq! # in case any are being re-visited
1175
+ when Module
1176
+ if !prev_entries.include?(types_entry)
1177
+ prev_entries << types_entry
1178
+ end
1179
+ else
1180
+ raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
1181
+ end
1182
+ else
1183
+ if types_entry.is_a?(Array)
1184
+ types_entry.uniq!
1185
+ end
1186
+ own_types[name] = types_entry
1187
+ end
1188
+ end
1189
+
1190
+ own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1191
+ own_union_memberships.merge!(addition.union_memberships)
1192
+
1193
+ addition.references.each { |thing, pointers|
1194
+ pointers.each { |pointer| references_to(thing, from: pointer) }
1195
+ }
1196
+
1197
+ addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
1198
+
1199
+ addition.arguments_with_default_values.each do |arg|
1200
+ arg.validate_default_value
1201
+ end
1202
+ end
1203
+
1595
1204
  def lazy_methods
1596
1205
  if !defined?(@lazy_methods)
1597
1206
  if inherited_map = find_inherited_value(:lazy_methods)
@@ -1600,6 +1209,7 @@ module GraphQL
1600
1209
  else
1601
1210
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1602
1211
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1212
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1603
1213
  end
1604
1214
  end
1605
1215
  @lazy_methods
@@ -1617,10 +1227,6 @@ module GraphQL
1617
1227
  @own_plugins ||= []
1618
1228
  end
1619
1229
 
1620
- def own_rescues
1621
- @own_rescues ||= {}
1622
- end
1623
-
1624
1230
  def own_orphan_types
1625
1231
  @own_orphan_types ||= []
1626
1232
  end
@@ -1649,263 +1255,12 @@ module GraphQL
1649
1255
  @defined_query_analyzers ||= []
1650
1256
  end
1651
1257
 
1652
- def all_middleware
1653
- find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1654
- end
1655
-
1656
- def own_middleware
1657
- @own_middleware ||= []
1658
- end
1659
-
1660
1258
  def own_multiplex_analyzers
1661
1259
  @own_multiplex_analyzers ||= []
1662
1260
  end
1663
-
1664
- # @param t [Module, Array<Module>]
1665
- # @return [void]
1666
- def add_type_and_traverse(t, root:)
1667
- if root
1668
- @root_types ||= []
1669
- @root_types << t
1670
- end
1671
- late_types = []
1672
- new_types = Array(t)
1673
- new_types.each { |t| add_type(t, owner: nil, late_types: late_types) }
1674
- missed_late_types = 0
1675
- while (late_type_vals = late_types.shift)
1676
- type_owner, lt = late_type_vals
1677
- if lt.is_a?(String)
1678
- type = Member::BuildType.constantize(lt)
1679
- # Reset the counter, since we might succeed next go-round
1680
- missed_late_types = 0
1681
- update_type_owner(type_owner, type)
1682
- add_type(type, owner: type_owner, late_types: late_types)
1683
- elsif lt.is_a?(LateBoundType)
1684
- if (type = get_type(lt.graphql_name))
1685
- # Reset the counter, since we might succeed next go-round
1686
- missed_late_types = 0
1687
- update_type_owner(type_owner, type)
1688
- add_type(type, owner: type_owner, late_types: late_types)
1689
- else
1690
- missed_late_types += 1
1691
- # Add it back to the list, maybe we'll be able to resolve it later.
1692
- late_types << [type_owner, lt]
1693
- if missed_late_types == late_types.size
1694
- # We've looked at all of them and haven't resolved one.
1695
- raise UnresolvedLateBoundTypeError.new(type: lt)
1696
- else
1697
- # Try the next one
1698
- end
1699
- end
1700
- else
1701
- raise ArgumentError, "Unexpected late type: #{lt.inspect}"
1702
- end
1703
- end
1704
- nil
1705
- end
1706
-
1707
- def update_type_owner(owner, type)
1708
- case owner
1709
- when Class
1710
- if owner.kind.union?
1711
- # It's a union with possible_types
1712
- # Replace the item by class name
1713
- owner.type_memberships.each { |tm|
1714
- possible_type = tm.object_type
1715
- if possible_type.is_a?(String) && (possible_type == type.name)
1716
- # This is a match of Ruby class names, not graphql names,
1717
- # since strings are used to refer to constants.
1718
- tm.object_type = type
1719
- elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == type.graphql_name
1720
- tm.object_type = type
1721
- end
1722
- }
1723
- own_possible_types[owner.graphql_name] = owner.possible_types
1724
- elsif type.kind.interface? && owner.kind.object?
1725
- new_interfaces = owner.interfaces.map do |t|
1726
- if t.is_a?(String) && t == type.graphql_name
1727
- type
1728
- elsif t.is_a?(LateBoundType) && t.graphql_name == type.graphql_name
1729
- type
1730
- else
1731
- t
1732
- end
1733
- end
1734
- owner.implements(*new_interfaces)
1735
- end
1736
-
1737
- when nil
1738
- # It's a root type
1739
- own_types[type.graphql_name] = type
1740
- when GraphQL::Schema::Field, GraphQL::Schema::Argument
1741
- orig_type = owner.type
1742
- # Apply list/non-null wrapper as needed
1743
- if orig_type.respond_to?(:of_type)
1744
- transforms = []
1745
- while (orig_type.respond_to?(:of_type))
1746
- if orig_type.kind.non_null?
1747
- transforms << :to_non_null_type
1748
- elsif orig_type.kind.list?
1749
- transforms << :to_list_type
1750
- else
1751
- raise "Invariant: :of_type isn't non-null or list"
1752
- end
1753
- orig_type = orig_type.of_type
1754
- end
1755
- transforms.reverse_each { |t| type = type.public_send(t) }
1756
- end
1757
- owner.type = type
1758
- else
1759
- raise "Unexpected update: #{owner.inspect} #{type.inspect}"
1760
- end
1761
- end
1762
-
1763
- def add_type(type, owner:, late_types:)
1764
- if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
1765
- type_class = type.metadata[:type_class]
1766
- if type_class.nil?
1767
- raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
1768
- else
1769
- type = type_class
1770
- end
1771
- elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
1772
- late_types << [owner, type]
1773
- return
1774
- end
1775
-
1776
- if owner.is_a?(Class) && owner < GraphQL::Schema::Union
1777
- um = own_union_memberships[type.graphql_name] ||= []
1778
- um << owner
1779
- end
1780
-
1781
- if (prev_type = own_types[type.graphql_name])
1782
- if prev_type != type
1783
- raise ArgumentError, "Conflicting type definitions for `#{type.graphql_name}`: #{prev_type} (#{prev_type.class}), #{type} #{type.class}"
1784
- else
1785
- # This type was already added
1786
- end
1787
- elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
1788
- type.arguments.each do |_name, arg|
1789
- arg_type = arg.type.unwrap
1790
- references_to(arg_type, from: arg)
1791
- add_type(arg_type, owner: arg, late_types: late_types)
1792
- end
1793
- else
1794
- own_types[type.graphql_name] = type
1795
- if type.kind.fields?
1796
- type.fields.each do |_name, field|
1797
- field_type = field.type.unwrap
1798
- references_to(field_type, from: field)
1799
- add_type(field_type, owner: field, late_types: late_types)
1800
- field.arguments.each do |_name, arg|
1801
- arg_type = arg.type.unwrap
1802
- references_to(arg_type, from: arg)
1803
- add_type(arg_type, owner: arg, late_types: late_types)
1804
- end
1805
- end
1806
- end
1807
- if type.kind.input_object?
1808
- type.arguments.each do |_name, arg|
1809
- arg_type = arg.type.unwrap
1810
- references_to(arg_type, from: arg)
1811
- add_type(arg_type, owner: arg, late_types: late_types)
1812
- end
1813
- end
1814
- if type.kind.union?
1815
- own_possible_types[type.graphql_name] = type.possible_types
1816
- type.possible_types.each do |t|
1817
- add_type(t, owner: type, late_types: late_types)
1818
- end
1819
- end
1820
- if type.kind.interface?
1821
- type.orphan_types.each do |t|
1822
- add_type(t, owner: type, late_types: late_types)
1823
- end
1824
- end
1825
- if type.kind.object?
1826
- own_possible_types[type.graphql_name] = [type]
1827
- type.interfaces.each do |i|
1828
- implementers = own_possible_types[i.graphql_name] ||= []
1829
- implementers << type
1830
- add_type(i, owner: type, late_types: late_types)
1831
- end
1832
- end
1833
- end
1834
- end
1835
1261
  end
1836
1262
 
1837
- # Call the given block at the right time, either:
1838
- # - Right away, if `value` is not registered with `lazy_resolve`
1839
- # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1840
- # @api private
1841
- def after_lazy(value)
1842
- if lazy?(value)
1843
- GraphQL::Execution::Lazy.new do
1844
- result = sync_lazy(value)
1845
- # The returned result might also be lazy, so check it, too
1846
- after_lazy(result) do |final_result|
1847
- yield(final_result) if block_given?
1848
- end
1849
- end
1850
- else
1851
- yield(value) if block_given?
1852
- end
1853
- end
1854
-
1855
- # @see Schema.sync_lazy for a hook to override
1856
- # @api private
1857
- def sync_lazy(value)
1858
- lazy_method = lazy_method_name(value)
1859
- if lazy_method
1860
- synced_value = value.public_send(lazy_method)
1861
- sync_lazy(synced_value)
1862
- else
1863
- value
1864
- end
1865
- end
1866
-
1867
- protected
1868
-
1869
- def rescues?
1870
- !!@rescue_middleware
1871
- end
1872
-
1873
- # Lazily create a middleware and add it to the schema
1874
- # (Don't add it if it's not used)
1875
- def rescue_middleware
1876
- @rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
1877
- end
1878
-
1879
- private
1880
-
1881
- def rebuild_artifacts
1882
- if @rebuilding_artifacts
1883
- 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."
1884
- else
1885
- @rebuilding_artifacts = true
1886
- @introspection_system = Schema::IntrospectionSystem.new(self)
1887
- traversal = Traversal.new(self)
1888
- @types = traversal.type_map
1889
- @root_types = [query, mutation, subscription]
1890
- @instrumented_field_map = traversal.instrumented_field_map
1891
- @type_reference_map = traversal.type_reference_map
1892
- @union_memberships = traversal.union_memberships
1893
- @find_cache = {}
1894
- @finder = Finder.new(self)
1895
- end
1896
- ensure
1897
- @rebuilding_artifacts = false
1898
- end
1899
-
1900
- class CyclicalDefinitionError < GraphQL::Error
1901
- end
1902
-
1903
- def with_definition_error_check
1904
- if @definition_error
1905
- raise @definition_error
1906
- else
1907
- yield
1908
- end
1909
- end
1263
+ # Install these here so that subclasses will also install it.
1264
+ self.connections = GraphQL::Pagination::Connections.new(schema: self)
1910
1265
  end
1911
1266
  end