graphql 1.10.2 → 2.0.21

Sign up to get free protection for your applications and to get access to all the features.
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