graphql 1.9.21 → 2.0.16

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

Potentially problematic release.


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

Files changed (403) 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 +25 -27
  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 +31 -2
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
  51. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  52. data/lib/graphql/analysis/ast/visitor.rb +17 -8
  53. data/lib/graphql/analysis/ast.rb +14 -14
  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 +37 -16
  57. data/lib/graphql/backtrace/traced_error.rb +0 -1
  58. data/lib/graphql/backtrace/tracer.rb +39 -9
  59. data/lib/graphql/backtrace.rb +20 -17
  60. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  61. data/lib/graphql/dataloader/request.rb +19 -0
  62. data/lib/graphql/dataloader/request_all.rb +19 -0
  63. data/lib/graphql/dataloader/source.rb +164 -0
  64. data/lib/graphql/dataloader.rb +311 -0
  65. data/lib/graphql/date_encoding_error.rb +16 -0
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/dig.rb +1 -1
  68. data/lib/graphql/execution/directive_checks.rb +2 -2
  69. data/lib/graphql/execution/errors.rb +77 -45
  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 +105 -0
  73. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  74. data/lib/graphql/execution/interpreter/resolve.rb +44 -25
  75. data/lib/graphql/execution/interpreter/runtime.rb +755 -395
  76. data/lib/graphql/execution/interpreter.rb +201 -74
  77. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  78. data/lib/graphql/execution/lazy.rb +5 -9
  79. data/lib/graphql/execution/lookahead.rb +65 -136
  80. data/lib/graphql/execution/multiplex.rb +5 -152
  81. data/lib/graphql/execution.rb +11 -4
  82. data/lib/graphql/filter.rb +1 -1
  83. data/lib/graphql/integer_decoding_error.rb +17 -0
  84. data/lib/graphql/integer_encoding_error.rb +18 -2
  85. data/lib/graphql/introspection/base_object.rb +2 -5
  86. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  87. data/lib/graphql/introspection/directive_type.rb +11 -5
  88. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  89. data/lib/graphql/introspection/entry_points.rb +5 -18
  90. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  91. data/lib/graphql/introspection/field_type.rb +9 -5
  92. data/lib/graphql/introspection/input_value_type.rb +41 -11
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +10 -10
  95. data/lib/graphql/introspection/type_type.rb +34 -17
  96. data/lib/graphql/introspection.rb +100 -0
  97. data/lib/graphql/invalid_null_error.rb +18 -0
  98. data/lib/graphql/language/block_string.rb +20 -5
  99. data/lib/graphql/language/cache.rb +37 -0
  100. data/lib/graphql/language/definition_slice.rb +21 -10
  101. data/lib/graphql/language/document_from_schema_definition.rb +104 -68
  102. data/lib/graphql/language/lexer.rb +83 -40
  103. data/lib/graphql/language/lexer.rl +31 -9
  104. data/lib/graphql/language/nodes.rb +64 -93
  105. data/lib/graphql/language/parser.rb +940 -896
  106. data/lib/graphql/language/parser.y +130 -103
  107. data/lib/graphql/language/printer.rb +48 -23
  108. data/lib/graphql/language/sanitized_printer.rb +222 -0
  109. data/lib/graphql/language/token.rb +0 -4
  110. data/lib/graphql/language/visitor.rb +2 -2
  111. data/lib/graphql/language.rb +3 -1
  112. data/lib/graphql/name_validator.rb +2 -7
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  114. data/lib/graphql/pagination/array_connection.rb +79 -0
  115. data/lib/graphql/pagination/connection.rb +253 -0
  116. data/lib/graphql/pagination/connections.rb +135 -0
  117. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  118. data/lib/graphql/pagination/relation_connection.rb +228 -0
  119. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  120. data/lib/graphql/pagination.rb +6 -0
  121. data/lib/graphql/parse_error.rb +0 -1
  122. data/lib/graphql/query/context.rb +172 -198
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +33 -7
  125. data/lib/graphql/query/null_context.rb +21 -8
  126. data/lib/graphql/query/validation_pipeline.rb +16 -38
  127. data/lib/graphql/query/variable_validation_error.rb +3 -3
  128. data/lib/graphql/query/variables.rb +39 -12
  129. data/lib/graphql/query.rb +74 -38
  130. data/lib/graphql/railtie.rb +6 -102
  131. data/lib/graphql/rake_task/validate.rb +4 -1
  132. data/lib/graphql/rake_task.rb +41 -10
  133. data/lib/graphql/relay/range_add.rb +17 -10
  134. data/lib/graphql/relay.rb +0 -15
  135. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  136. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  137. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  138. data/lib/graphql/rubocop.rb +4 -0
  139. data/lib/graphql/schema/addition.rb +245 -0
  140. data/lib/graphql/schema/argument.rb +286 -31
  141. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  142. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  143. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  144. data/lib/graphql/schema/build_from_definition.rb +334 -220
  145. data/lib/graphql/schema/built_in_types.rb +5 -5
  146. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  147. data/lib/graphql/schema/directive/feature.rb +1 -1
  148. data/lib/graphql/schema/directive/flagged.rb +57 -0
  149. data/lib/graphql/schema/directive/include.rb +2 -2
  150. data/lib/graphql/schema/directive/one_of.rb +12 -0
  151. data/lib/graphql/schema/directive/skip.rb +2 -2
  152. data/lib/graphql/schema/directive/transform.rb +14 -2
  153. data/lib/graphql/schema/directive.rb +117 -14
  154. data/lib/graphql/schema/enum.rb +113 -22
  155. data/lib/graphql/schema/enum_value.rb +16 -21
  156. data/lib/graphql/schema/field/connection_extension.rb +50 -20
  157. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  158. data/lib/graphql/schema/field.rb +491 -329
  159. data/lib/graphql/schema/field_extension.rb +89 -2
  160. data/lib/graphql/schema/find_inherited_value.rb +17 -1
  161. data/lib/graphql/schema/finder.rb +16 -14
  162. data/lib/graphql/schema/input_object.rb +182 -60
  163. data/lib/graphql/schema/interface.rb +28 -43
  164. data/lib/graphql/schema/introspection_system.rb +101 -38
  165. data/lib/graphql/schema/late_bound_type.rb +7 -2
  166. data/lib/graphql/schema/list.rb +61 -3
  167. data/lib/graphql/schema/loader.rb +144 -102
  168. data/lib/graphql/schema/member/base_dsl_methods.rb +33 -32
  169. data/lib/graphql/schema/member/build_type.rb +24 -15
  170. data/lib/graphql/schema/member/has_arguments.rb +261 -24
  171. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  172. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  173. data/lib/graphql/schema/member/has_directives.rb +113 -0
  174. data/lib/graphql/schema/member/has_fields.rb +99 -34
  175. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  176. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  177. data/lib/graphql/schema/member/has_validators.rb +31 -0
  178. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  179. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  180. data/lib/graphql/schema/member/validates_input.rb +33 -0
  181. data/lib/graphql/schema/member.rb +11 -6
  182. data/lib/graphql/schema/mutation.rb +4 -9
  183. data/lib/graphql/schema/non_null.rb +34 -4
  184. data/lib/graphql/schema/object.rb +38 -60
  185. data/lib/graphql/schema/printer.rb +16 -35
  186. data/lib/graphql/schema/relay_classic_mutation.rb +90 -43
  187. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -6
  188. data/lib/graphql/schema/resolver.rb +146 -93
  189. data/lib/graphql/schema/scalar.rb +40 -15
  190. data/lib/graphql/schema/subscription.rb +55 -26
  191. data/lib/graphql/schema/timeout.rb +29 -15
  192. data/lib/graphql/schema/type_expression.rb +21 -13
  193. data/lib/graphql/schema/type_membership.rb +22 -5
  194. data/lib/graphql/schema/union.rb +48 -14
  195. data/lib/graphql/schema/unique_within_type.rb +1 -2
  196. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  197. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  198. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  199. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  200. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  201. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  202. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  203. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  204. data/lib/graphql/schema/validator.rb +171 -0
  205. data/lib/graphql/schema/warden.rb +187 -33
  206. data/lib/graphql/schema/wrapper.rb +0 -5
  207. data/lib/graphql/schema.rb +773 -892
  208. data/lib/graphql/static_validation/all_rules.rb +3 -0
  209. data/lib/graphql/static_validation/base_visitor.rb +21 -31
  210. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  211. data/lib/graphql/static_validation/error.rb +3 -1
  212. data/lib/graphql/static_validation/literal_validator.rb +55 -26
  213. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  215. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  216. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  225. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  226. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  227. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  228. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  229. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  230. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  231. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  232. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  233. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  234. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  235. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  236. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  238. data/lib/graphql/static_validation/type_stack.rb +2 -2
  239. data/lib/graphql/static_validation/validation_context.rb +13 -3
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +31 -19
  242. data/lib/graphql/static_validation.rb +1 -2
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +129 -22
  245. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  246. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  247. data/lib/graphql/subscriptions/event.rb +85 -31
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -47
  249. data/lib/graphql/subscriptions/serialize.rb +53 -6
  250. data/lib/graphql/subscriptions.rb +137 -57
  251. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  252. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  253. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  254. data/lib/graphql/tracing/data_dog_tracing.rb +34 -2
  255. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +67 -38
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  260. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  261. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  262. data/lib/graphql/tracing.rb +15 -36
  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 -90
  268. data/lib/graphql/types/relay/base_edge.rb +2 -34
  269. data/lib/graphql/types/relay/connection_behaviors.rb +158 -0
  270. data/lib/graphql/types/relay/default_relay.rb +27 -0
  271. data/lib/graphql/types/relay/edge_behaviors.rb +65 -0
  272. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  273. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  274. data/lib/graphql/types/relay/node.rb +2 -4
  275. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -5
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +2 -2
  281. data/lib/graphql/unresolved_type_error.rb +2 -2
  282. data/lib/graphql/version.rb +1 -1
  283. data/lib/graphql.rb +41 -58
  284. data/readme.md +3 -6
  285. metadata +103 -237
  286. data/lib/graphql/analysis/analyze_query.rb +0 -91
  287. data/lib/graphql/analysis/field_usage.rb +0 -45
  288. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  289. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  290. data/lib/graphql/analysis/query_complexity.rb +0 -88
  291. data/lib/graphql/analysis/query_depth.rb +0 -43
  292. data/lib/graphql/analysis/reducer_state.rb +0 -48
  293. data/lib/graphql/argument.rb +0 -159
  294. data/lib/graphql/authorization.rb +0 -82
  295. data/lib/graphql/backwards_compatibility.rb +0 -60
  296. data/lib/graphql/base_type.rb +0 -226
  297. data/lib/graphql/boolean_type.rb +0 -2
  298. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  299. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  300. data/lib/graphql/compatibility/execution_specification.rb +0 -435
  301. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  302. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
  303. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
  304. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  305. data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
  306. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
  307. data/lib/graphql/compatibility.rb +0 -5
  308. data/lib/graphql/define/assign_argument.rb +0 -12
  309. data/lib/graphql/define/assign_connection.rb +0 -13
  310. data/lib/graphql/define/assign_enum_value.rb +0 -18
  311. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  312. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  313. data/lib/graphql/define/assign_object_field.rb +0 -42
  314. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  315. data/lib/graphql/define/instance_definable.rb +0 -311
  316. data/lib/graphql/define/no_definition_error.rb +0 -7
  317. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  318. data/lib/graphql/define/type_definer.rb +0 -31
  319. data/lib/graphql/define.rb +0 -31
  320. data/lib/graphql/deprecated_dsl.rb +0 -42
  321. data/lib/graphql/directive/deprecated_directive.rb +0 -13
  322. data/lib/graphql/directive/include_directive.rb +0 -2
  323. data/lib/graphql/directive/skip_directive.rb +0 -2
  324. data/lib/graphql/directive.rb +0 -104
  325. data/lib/graphql/enum_type.rb +0 -193
  326. data/lib/graphql/execution/execute.rb +0 -326
  327. data/lib/graphql/execution/flatten.rb +0 -40
  328. data/lib/graphql/execution/instrumentation.rb +0 -92
  329. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  330. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  331. data/lib/graphql/execution/typecast.rb +0 -50
  332. data/lib/graphql/field/resolve.rb +0 -59
  333. data/lib/graphql/field.rb +0 -330
  334. data/lib/graphql/float_type.rb +0 -2
  335. data/lib/graphql/function.rb +0 -153
  336. data/lib/graphql/id_type.rb +0 -2
  337. data/lib/graphql/input_object_type.rb +0 -154
  338. data/lib/graphql/int_type.rb +0 -2
  339. data/lib/graphql/interface_type.rb +0 -86
  340. data/lib/graphql/internal_representation/document.rb +0 -27
  341. data/lib/graphql/internal_representation/node.rb +0 -206
  342. data/lib/graphql/internal_representation/print.rb +0 -51
  343. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  344. data/lib/graphql/internal_representation/scope.rb +0 -88
  345. data/lib/graphql/internal_representation/visit.rb +0 -36
  346. data/lib/graphql/internal_representation.rb +0 -7
  347. data/lib/graphql/list_type.rb +0 -80
  348. data/lib/graphql/literal_validation_error.rb +0 -6
  349. data/lib/graphql/non_null_type.rb +0 -81
  350. data/lib/graphql/object_type.rb +0 -141
  351. data/lib/graphql/query/arguments.rb +0 -187
  352. data/lib/graphql/query/arguments_cache.rb +0 -25
  353. data/lib/graphql/query/executor.rb +0 -53
  354. data/lib/graphql/query/literal_input.rb +0 -116
  355. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  356. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  357. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  358. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  359. data/lib/graphql/query/serial_execution.rb +0 -39
  360. data/lib/graphql/relay/array_connection.rb +0 -85
  361. data/lib/graphql/relay/base_connection.rb +0 -172
  362. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  363. data/lib/graphql/relay/connection_resolve.rb +0 -43
  364. data/lib/graphql/relay/connection_type.rb +0 -40
  365. data/lib/graphql/relay/edge.rb +0 -27
  366. data/lib/graphql/relay/edge_type.rb +0 -18
  367. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  368. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  369. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  370. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  371. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  372. data/lib/graphql/relay/mutation/result.rb +0 -38
  373. data/lib/graphql/relay/mutation.rb +0 -190
  374. data/lib/graphql/relay/node.rb +0 -36
  375. data/lib/graphql/relay/page_info.rb +0 -7
  376. data/lib/graphql/relay/relation_connection.rb +0 -190
  377. data/lib/graphql/relay/type_extensions.rb +0 -30
  378. data/lib/graphql/scalar_type.rb +0 -133
  379. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  380. data/lib/graphql/schema/default_parse_error.rb +0 -10
  381. data/lib/graphql/schema/default_type_error.rb +0 -15
  382. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  383. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
  384. data/lib/graphql/schema/member/instrumentation.rb +0 -132
  385. data/lib/graphql/schema/middleware_chain.rb +0 -82
  386. data/lib/graphql/schema/possible_types.rb +0 -39
  387. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  388. data/lib/graphql/schema/timeout_middleware.rb +0 -86
  389. data/lib/graphql/schema/traversal.rb +0 -228
  390. data/lib/graphql/schema/validation.rb +0 -303
  391. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  392. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  393. data/lib/graphql/string_type.rb +0 -2
  394. data/lib/graphql/subscriptions/subscription_root.rb +0 -74
  395. data/lib/graphql/tracing/skylight_tracing.rb +0 -62
  396. data/lib/graphql/types/relay/base_field.rb +0 -22
  397. data/lib/graphql/types/relay/base_interface.rb +0 -29
  398. data/lib/graphql/types/relay/base_object.rb +0 -26
  399. data/lib/graphql/types/relay/node_field.rb +0 -43
  400. data/lib/graphql/types/relay/nodes_field.rb +0 -45
  401. data/lib/graphql/union_type.rb +0 -135
  402. data/lib/graphql/upgrader/member.rb +0 -936
  403. 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"
@@ -36,9 +29,12 @@ require "graphql/schema/scalar"
36
29
  require "graphql/schema/object"
37
30
  require "graphql/schema/union"
38
31
  require "graphql/schema/directive"
32
+ require "graphql/schema/directive/deprecated"
39
33
  require "graphql/schema/directive/include"
34
+ require "graphql/schema/directive/one_of"
40
35
  require "graphql/schema/directive/skip"
41
36
  require "graphql/schema/directive/feature"
37
+ require "graphql/schema/directive/flagged"
42
38
  require "graphql/schema/directive/transform"
43
39
  require "graphql/schema/type_membership"
44
40
 
@@ -55,7 +51,6 @@ module GraphQL
55
51
  # - types for exposing your application
56
52
  # - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
57
53
  # - execution strategies for running incoming queries
58
- # - middleware for interacting with execution
59
54
  #
60
55
  # Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
61
56
  # The schema will traverse the tree of fields & types, using those as starting points.
@@ -67,802 +62,457 @@ 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
- #
71
- # A schema accepts a `Relay::GlobalNodeIdentification` instance for use with Relay IDs.
72
- #
65
+ # #
73
66
  # @example defining a schema
74
- # MySchema = GraphQL::Schema.define do
67
+ # class MySchema < GraphQL::Schema
75
68
  # query QueryType
76
- # middleware PermissionMiddleware
77
- # rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
78
69
  # # If types are only connected by way of interfaces, they must be added here
79
70
  # orphan_types ImageType, AudioType
80
71
  # end
81
72
  #
82
73
  class Schema
83
- extend Forwardable
84
- extend GraphQL::Schema::Member::AcceptsDefinition
85
- include GraphQL::Define::InstanceDefinable
74
+ extend GraphQL::Schema::Member::HasAstNode
86
75
  extend GraphQL::Schema::FindInheritedValue
87
76
 
88
- accepts_definitions \
89
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
90
- :max_depth, :max_complexity, :default_max_page_size,
91
- :orphan_types, :resolve_type, :type_error, :parse_error,
92
- :error_bubbling,
93
- :raise_definition_error,
94
- :object_from_id, :id_from_object,
95
- :default_mask,
96
- :cursor_encoder,
97
- # If these are given as classes, normalize them. Accept `nil` when building from string.
98
- query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
99
- mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
100
- subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
101
- disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
102
- disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
103
- disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
104
- directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m } },
105
- directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
106
- instrument: ->(schema, type, instrumenter, after_built_ins: false) {
107
- if type == :field && after_built_ins
108
- type = :field_after_built_ins
109
- end
110
- schema.instrumenters[type] << instrumenter
111
- },
112
- query_analyzer: ->(schema, analyzer) {
113
- if analyzer == GraphQL::Authorization::Analyzer
114
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
115
- end
116
- schema.query_analyzers << analyzer
117
- },
118
- multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
119
- middleware: ->(schema, middleware) { schema.middleware << middleware },
120
- lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
121
- rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
122
- tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
123
-
124
- ensure_defined :introspection_system
125
-
126
- attr_accessor \
127
- :query, :mutation, :subscription,
128
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
129
- :max_depth, :max_complexity, :default_max_page_size,
130
- :orphan_types, :directives,
131
- :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
132
- :cursor_encoder,
133
- :ast_node,
134
- :raise_definition_error,
135
- :introspection_namespace,
136
- :analysis_engine
137
-
138
- # [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
139
- attr_accessor :error_bubbling
140
-
141
- # Single, long-lived instance of the provided subscriptions class, if there is one.
142
- # @return [GraphQL::Subscriptions]
143
- attr_accessor :subscriptions
144
-
145
- # @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
146
- attr_accessor :middleware
147
-
148
- # @return [<#call(member, ctx)>] A callable for filtering members of the schema
149
- # @see {Query.new} for query-specific filters with `except:`
150
- attr_accessor :default_mask
151
-
152
- # @see {GraphQL::Query::Context} The parent class of these classes
153
- # @return [Class] Instantiated for each query
154
- attr_accessor :context_class
155
-
156
- # [Boolean] True if this object disables the introspection entry point fields
157
- attr_accessor :disable_introspection_entry_points
158
-
159
- # [Boolean] True if this object disables the __schema introspection entry point field
160
- attr_accessor :disable_schema_introspection_entry_point
161
-
162
- # [Boolean] True if this object disables the __type introspection entry point field
163
- attr_accessor :disable_type_introspection_entry_point
164
-
165
- class << self
166
- attr_writer :default_execution_strategy
167
- end
168
-
169
- def default_filter
170
- GraphQL::Filter.new(except: default_mask)
171
- end
172
-
173
- # @return [Array<#trace(key, data)>] Tracers applied to every query
174
- # @see {Query#tracers} for query-specific tracers
175
- attr_reader :tracers
176
-
177
- DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
178
- EMPTY_ARRAY = [].freeze
179
- EMPTY_HASH = {}.freeze
180
-
181
- attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
182
-
183
- def initialize
184
- @tracers = []
185
- @definition_error = nil
186
- @orphan_types = []
187
- @directives = self.class.default_directives
188
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
189
- @middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
190
- @query_analyzers = []
191
- @multiplex_analyzers = []
192
- @resolve_type_proc = nil
193
- @object_from_id_proc = nil
194
- @id_from_object_proc = nil
195
- @type_error_proc = DefaultTypeError
196
- @parse_error_proc = DefaultParseError
197
- @instrumenters = Hash.new { |h, k| h[k] = [] }
198
- @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
199
- @lazy_methods.set(GraphQL::Execution::Lazy, :value)
200
- @cursor_encoder = Base64Encoder
201
- # Default to the built-in execution strategy:
202
- @analysis_engine = GraphQL::Analysis
203
- @query_execution_strategy = self.class.default_execution_strategy
204
- @mutation_execution_strategy = self.class.default_execution_strategy
205
- @subscription_execution_strategy = self.class.default_execution_strategy
206
- @default_mask = GraphQL::Schema::NullMask
207
- @rebuilding_artifacts = false
208
- @context_class = GraphQL::Query::Context
209
- @introspection_namespace = nil
210
- @introspection_system = nil
211
- @interpreter = false
212
- @error_bubbling = false
213
- @disable_introspection_entry_points = false
214
- @disable_schema_introspection_entry_point = false
215
- @disable_type_introspection_entry_point = false
216
- end
217
-
218
- # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
219
- def interpreter?
220
- @interpreter
221
- end
222
-
223
- # @api private
224
- attr_writer :interpreter
225
-
226
- def inspect
227
- "#<#{self.class.name} ...>"
228
- end
229
-
230
- def initialize_copy(other)
231
- super
232
- @orphan_types = other.orphan_types.dup
233
- @directives = other.directives.dup
234
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
235
- @middleware = other.middleware.dup
236
- @query_analyzers = other.query_analyzers.dup
237
- @multiplex_analyzers = other.multiplex_analyzers.dup
238
- @tracers = other.tracers.dup
239
- @possible_types = GraphQL::Schema::PossibleTypes.new(self)
240
-
241
- @lazy_methods = other.lazy_methods.dup
242
-
243
- @instrumenters = Hash.new { |h, k| h[k] = [] }
244
- other.instrumenters.each do |key, insts|
245
- @instrumenters[key].concat(insts)
246
- end
247
-
248
- if other.rescues?
249
- @rescue_middleware = other.rescue_middleware
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
+ )
250
84
  end
251
-
252
- # This will be rebuilt when it's requested
253
- # or during a later `define` call
254
- @types = nil
255
- @introspection_system = nil
256
- end
257
-
258
- def rescue_from(*args, &block)
259
- rescue_middleware.rescue_from(*args, &block)
260
- end
261
-
262
- def remove_handler(*args, &block)
263
- rescue_middleware.remove_handler(*args, &block)
264
85
  end
265
86
 
266
- def using_ast_analysis?
267
- @analysis_engine == GraphQL::Analysis::AST
268
- end
269
-
270
- # For forwards-compatibility with Schema classes
271
- alias :graphql_definition :itself
272
-
273
- # Validate a query string according to this schema.
274
- # @param string_or_document [String, GraphQL::Language::Nodes::Document]
275
- # @return [Array<GraphQL::StaticValidation::Error >]
276
- def validate(string_or_document, rules: nil, context: nil)
277
- doc = if string_or_document.is_a?(String)
278
- GraphQL.parse(string_or_document)
279
- else
280
- string_or_document
281
- end
282
- query = GraphQL::Query.new(self, document: doc, context: context)
283
- validator_opts = { schema: self }
284
- rules && (validator_opts[:rules] = rules)
285
- validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
286
- res = validator.validate(query)
287
- res[:errors]
87
+ class UnresolvedLateBoundTypeError < GraphQL::Error
88
+ attr_reader :type
89
+ def initialize(type:)
90
+ @type = type
91
+ super("Late bound type was never found: #{type.inspect}")
92
+ end
288
93
  end
289
94
 
290
- def define(**kwargs, &block)
291
- super
292
- ensure_defined
293
- # Assert that all necessary configs are present:
294
- validation_error = Validation.validate(self)
295
- validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
296
- rebuild_artifacts
297
-
298
- @definition_error = nil
299
- nil
300
- rescue StandardError => err
301
- if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
302
- raise
303
- else
304
- # Raise this error _later_ to avoid messing with Rails constant loading
305
- @definition_error = err
306
- end
307
- nil
308
- end
95
+ # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
96
+ class InvalidDocumentError < Error; end;
309
97
 
310
- # Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
311
- # @param instrumentation_type [Symbol]
312
- # @param instrumenter
313
- # @return [void]
314
- def instrument(instrumentation_type, instrumenter)
315
- @instrumenters[instrumentation_type] << instrumenter
316
- if instrumentation_type == :field
317
- rebuild_artifacts
98
+ class << self
99
+ # Create schema with the result of an introspection query.
100
+ # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
101
+ # @return [Class<GraphQL::Schema>] the schema described by `input`
102
+ def from_introspection(introspection_result)
103
+ GraphQL::Schema::Loader.load(introspection_result)
104
+ end
105
+
106
+ # Create schema from an IDL schema or file containing an IDL definition.
107
+ # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
108
+ # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
109
+ # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
110
+ # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
111
+ # @return [Class] the schema described by `document`
112
+ def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
113
+ # If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
114
+ if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
115
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
116
+ self,
117
+ definition_or_path,
118
+ default_resolve: default_resolve,
119
+ parser: parser,
120
+ using: using,
121
+ )
122
+ else
123
+ GraphQL::Schema::BuildFromDefinition.from_definition(
124
+ self,
125
+ definition_or_path,
126
+ default_resolve: default_resolve,
127
+ parser: parser,
128
+ using: using,
129
+ )
130
+ end
318
131
  end
319
- end
320
132
 
321
- # @return [Array<GraphQL::BaseType>] The root types of this schema
322
- def root_types
323
- @root_types ||= begin
324
- rebuild_artifacts
325
- @root_types
133
+ def deprecated_graphql_definition
134
+ graphql_definition(silence_deprecation_warning: true)
326
135
  end
327
- end
328
136
 
329
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
330
- # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
331
- def types
332
- @types ||= begin
333
- rebuild_artifacts
334
- @types
137
+ # @return [GraphQL::Subscriptions]
138
+ def subscriptions(inherited: true)
139
+ defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
335
140
  end
336
- end
337
141
 
338
- # @api private
339
- def introspection_system
340
- @introspection_system ||= begin
341
- rebuild_artifacts
342
- @introspection_system
142
+ def subscriptions=(new_implementation)
143
+ @subscriptions = new_implementation
343
144
  end
344
- end
345
145
 
346
- # Returns a list of Arguments and Fields referencing a certain type
347
- # @param type_name [String]
348
- # @return [Hash]
349
- def references_to(type_name)
350
- rebuild_artifacts unless defined?(@type_reference_map)
351
- @type_reference_map.fetch(type_name, [])
352
- end
146
+ # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
147
+ # @see {#as_json}
148
+ # @return [String]
149
+ def to_json(**args)
150
+ JSON.pretty_generate(as_json(**args))
151
+ end
353
152
 
354
- # Returns a list of Union types in which a type is a member
355
- # @param type [GraphQL::ObjectType]
356
- # @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
357
- def union_memberships(type)
358
- rebuild_artifacts unless defined?(@union_memberships)
359
- @union_memberships.fetch(type.name, [])
360
- end
153
+ # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
154
+ # @param context [Hash]
155
+ # @param only [<#call(member, ctx)>]
156
+ # @param except [<#call(member, ctx)>]
157
+ # @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
158
+ # @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
159
+ # @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
160
+ # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
161
+ # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
162
+ # @return [Hash] GraphQL result
163
+ 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)
164
+ introspection_query = Introspection.query(
165
+ include_deprecated_args: include_deprecated_args,
166
+ include_schema_description: include_schema_description,
167
+ include_is_repeatable: include_is_repeatable,
168
+ include_is_one_of: include_is_one_of,
169
+ include_specified_by_url: include_specified_by_url,
170
+ )
361
171
 
362
- # Execute a query on itself. Raises an error if the schema definition is invalid.
363
- # @see {Query#initialize} for arguments.
364
- # @return [Hash] query result, ready to be serialized as JSON
365
- def execute(query_str = nil, **kwargs)
366
- if query_str
367
- kwargs[:query] = query_str
368
- end
369
- # Some of the query context _should_ be passed to the multiplex, too
370
- multiplex_context = if (ctx = kwargs[:context])
371
- {
372
- backtrace: ctx[:backtrace],
373
- tracers: ctx[:tracers],
374
- }
375
- else
376
- {}
172
+ execute(introspection_query, only: only, except: except, context: context).to_h
377
173
  end
378
- # Since we're running one query, don't run a multiplex-level complexity analyzer
379
- all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
380
- all_results[0]
381
- end
382
174
 
383
- # Execute several queries on itself. Raises an error if the schema definition is invalid.
384
- # @example Run several queries at once
385
- # context = { ... }
386
- # queries = [
387
- # { query: params[:query_1], variables: params[:variables_1], context: context },
388
- # { query: params[:query_2], variables: params[:variables_2], context: context },
389
- # ]
390
- # results = MySchema.multiplex(queries)
391
- # render json: {
392
- # result_1: results[0],
393
- # result_2: results[1],
394
- # }
395
- #
396
- # @see {Query#initialize} for query keyword arguments
397
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
398
- # @param queries [Array<Hash>] Keyword arguments for each query
399
- # @param context [Hash] Multiplex-level context
400
- # @return [Array<Hash>] One result for each query in the input
401
- def multiplex(queries, **kwargs)
402
- with_definition_error_check {
403
- GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
404
- }
405
- end
175
+ # Return the GraphQL IDL for the schema
176
+ # @param context [Hash]
177
+ # @param only [<#call(member, ctx)>]
178
+ # @param except [<#call(member, ctx)>]
179
+ # @return [String]
180
+ def to_definition(only: nil, except: nil, context: {})
181
+ GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
182
+ end
406
183
 
407
- # Search for a schema member using a string path
408
- # @example Finding a Field
409
- # Schema.find("Ensemble.musicians")
410
- #
411
- # @see {GraphQL::Schema::Finder} for more examples
412
- # @param path [String] A dot-separated path to the member
413
- # @raise [Schema::Finder::MemberNotFoundError] if path could not be found
414
- # @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
415
- def find(path)
416
- rebuild_artifacts unless defined?(@finder)
417
- @find_cache[path] ||= @finder.find(path)
418
- end
184
+ # Return the GraphQL::Language::Document IDL AST for the schema
185
+ # @return [GraphQL::Language::Document]
186
+ def to_document
187
+ GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
188
+ end
419
189
 
420
- # Resolve field named `field_name` for type `parent_type`.
421
- # Handles dynamic fields `__typename`, `__type` and `__schema`, too
422
- # @param parent_type [String, GraphQL::BaseType]
423
- # @param field_name [String]
424
- # @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
425
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
426
- def get_field(parent_type, field_name)
427
- with_definition_error_check do
428
- parent_type_name = case parent_type
429
- when GraphQL::BaseType
430
- parent_type.name
431
- when String
432
- parent_type
190
+ # @return [String, nil]
191
+ def description(new_description = nil)
192
+ if new_description
193
+ @description = new_description
194
+ elsif defined?(@description)
195
+ @description
433
196
  else
434
- raise "Unexpected parent_type: #{parent_type}"
197
+ find_inherited_value(:description, nil)
435
198
  end
199
+ end
436
200
 
437
- defined_field = @instrumented_field_map[parent_type_name][field_name]
438
- if defined_field
439
- defined_field
440
- elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
441
- entry_point_field
442
- elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
443
- dynamic_field
444
- else
445
- nil
201
+ def find(path)
202
+ if !@finder
203
+ @find_cache = {}
204
+ @finder ||= GraphQL::Schema::Finder.new(self)
446
205
  end
206
+ @find_cache[path] ||= @finder.find(path)
447
207
  end
448
- end
449
-
450
- # Fields for this type, after instrumentation is applied
451
- # @return [Hash<String, GraphQL::Field>]
452
- def get_fields(type)
453
- @instrumented_field_map[type.graphql_name]
454
- end
455
-
456
- def type_from_ast(ast_node)
457
- GraphQL::Schema::TypeExpression.build_type(self.types, ast_node)
458
- end
459
208
 
460
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
461
- # @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
462
- # @param context [GraphQL::Query::Context] The context for the current query
463
- # @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
464
- def possible_types(type_defn, context = GraphQL::Query::NullContext)
465
- @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
466
- @possible_types.possible_types(type_defn, context)
467
- end
468
-
469
- # @see [GraphQL::Schema::Warden] Resticted access to root types
470
- # @return [GraphQL::ObjectType, nil]
471
- def root_type_for_operation(operation)
472
- case operation
473
- when "query"
474
- query
475
- when "mutation"
476
- mutation
477
- when "subscription"
478
- subscription
479
- else
480
- raise ArgumentError, "unknown operation type: #{operation}"
209
+ def default_filter
210
+ GraphQL::Filter.new(except: default_mask)
481
211
  end
482
- end
483
212
 
484
- def execution_strategy_for_operation(operation)
485
- case operation
486
- when "query"
487
- query_execution_strategy
488
- when "mutation"
489
- mutation_execution_strategy
490
- when "subscription"
491
- subscription_execution_strategy
492
- else
493
- raise ArgumentError, "unknown operation type: #{operation}"
494
- end
495
- end
496
-
497
- # Determine the GraphQL type for a given object.
498
- # This is required for unions and interfaces (including Relay's `Node` interface)
499
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
500
- # @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
501
- # @param object [Any] An application object which GraphQL is currently resolving on
502
- # @param ctx [GraphQL::Query::Context] The context for the current query
503
- # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
504
- def resolve_type(type, object, ctx = :__undefined__)
505
- check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
506
- if @resolve_type_proc.nil?
507
- raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
213
+ def default_mask(new_mask = nil)
214
+ if new_mask
215
+ @own_default_mask = new_mask
216
+ else
217
+ @own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
508
218
  end
509
- @resolve_type_proc.call(ok_type, ok_object, ok_ctx)
510
- end
511
- end
512
-
513
- # This is a compatibility hack so that instance-level and class-level
514
- # methods can get correctness checks without calling one another
515
- # @api private
516
- def check_resolved_type(type, object, ctx = :__undefined__)
517
- if ctx == :__undefined__
518
- # Old method signature
519
- ctx = object
520
- object = type
521
- type = nil
522
219
  end
523
220
 
524
- if object.is_a?(GraphQL::Schema::Object)
525
- object = object.object
221
+ def static_validator
222
+ GraphQL::StaticValidation::Validator.new(schema: self)
526
223
  end
527
224
 
528
- if type.respond_to?(:graphql_definition)
529
- type = type.graphql_definition
225
+ def use(plugin, **kwargs)
226
+ if kwargs.any?
227
+ plugin.use(self, **kwargs)
228
+ else
229
+ plugin.use(self)
230
+ end
231
+ own_plugins << [plugin, kwargs]
530
232
  end
531
233
 
532
- # Prefer a type-local function; fall back to the schema-level function
533
- type_proc = type && type.resolve_type_proc
534
- type_result = if type_proc
535
- type_proc.call(object, ctx)
536
- else
537
- yield(type, object, ctx)
234
+ def plugins
235
+ find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
538
236
  end
539
237
 
540
- if type_result.nil?
541
- nil
542
- else
543
- after_lazy(type_result) do |resolved_type_result|
544
- if resolved_type_result.respond_to?(:graphql_definition)
545
- resolved_type_result = resolved_type_result.graphql_definition
546
- end
547
- if !resolved_type_result.is_a?(GraphQL::BaseType)
548
- type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
549
- raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
238
+ # Build a map of `{ name => type }` and return it
239
+ # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
240
+ # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
241
+ def types(context = GraphQL::Query::NullContext)
242
+ all_types = non_introspection_types.merge(introspection_system.types)
243
+ visible_types = {}
244
+ all_types.each do |k, v|
245
+ visible_types[k] =if v.is_a?(Array)
246
+ visible_t = nil
247
+ v.each do |t|
248
+ if t.visible?(context)
249
+ if visible_t.nil?
250
+ visible_t = t
251
+ else
252
+ raise DuplicateNamesError.new(
253
+ duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
254
+ )
255
+ end
256
+ end
257
+ end
258
+ visible_t
550
259
  else
551
- resolved_type_result
260
+ v
552
261
  end
553
262
  end
263
+ visible_types
554
264
  end
555
- end
556
265
 
557
- def resolve_type=(new_resolve_type_proc)
558
- callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
559
- @resolve_type_proc = callable
560
- end
266
+ # @param type_name [String]
267
+ # @return [Module, nil] A type, or nil if there's no type called `type_name`
268
+ def get_type(type_name, context = GraphQL::Query::NullContext)
269
+ local_entry = own_types[type_name]
270
+ type_defn = case local_entry
271
+ when nil
272
+ nil
273
+ when Array
274
+ visible_t = nil
275
+ warden = Warden.from_context(context)
276
+ local_entry.each do |t|
277
+ if warden.visible_type?(t, context)
278
+ if visible_t.nil?
279
+ visible_t = t
280
+ else
281
+ raise DuplicateNamesError.new(
282
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
283
+ )
284
+ end
285
+ end
286
+ end
287
+ visible_t
288
+ when Module
289
+ local_entry
290
+ else
291
+ raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
292
+ end
561
293
 
562
- # Fetch an application object by its unique id
563
- # @param id [String] A unique identifier, provided previously by this GraphQL schema
564
- # @param ctx [GraphQL::Query::Context] The context for the current query
565
- # @return [Any] The application object identified by `id`
566
- def object_from_id(id, ctx)
567
- if @object_from_id_proc.nil?
568
- raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
569
- else
570
- @object_from_id_proc.call(id, ctx)
294
+ type_defn ||
295
+ introspection_system.types[type_name] || # todo context-specific introspection?
296
+ (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
571
297
  end
572
- end
573
-
574
- # @param new_proc [#call] A new callable for fetching objects by ID
575
- def object_from_id=(new_proc)
576
- @object_from_id_proc = new_proc
577
- end
578
-
579
- # When we encounter a type error during query execution, we call this hook.
580
- #
581
- # You can use this hook to write a log entry,
582
- # add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
583
- # or raise an exception and halt query execution.
584
- #
585
- # @example A `nil` is encountered by a non-null field
586
- # type_error ->(err, query_ctx) {
587
- # err.is_a?(GraphQL::InvalidNullError) # => true
588
- # }
589
- #
590
- # @example An object doesn't resolve to one of a {UnionType}'s members
591
- # type_error ->(err, query_ctx) {
592
- # err.is_a?(GraphQL::UnresolvedTypeError) # => true
593
- # }
594
- #
595
- # @see {DefaultTypeError} is the default behavior.
596
- # @param err [GraphQL::TypeError] The error encountered during execution
597
- # @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
598
- # @return void
599
- def type_error(err, ctx)
600
- @type_error_proc.call(err, ctx)
601
- end
602
-
603
- # @param new_proc [#call] A new callable for handling type errors during execution
604
- def type_error=(new_proc)
605
- @type_error_proc = new_proc
606
- end
607
-
608
- # Can't delegate to `class`
609
- alias :_schema_class :class
610
- def_delegators :_schema_class, :visible?, :accessible?, :authorized?, :unauthorized_object, :unauthorized_field, :inaccessible_fields
611
- def_delegators :_schema_class, :directive
612
- def_delegators :_schema_class, :error_handler
613
-
614
- # A function to call when {#execute} receives an invalid query string
615
- #
616
- # @see {DefaultParseError} is the default behavior.
617
- # @param err [GraphQL::ParseError] The error encountered during parsing
618
- # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
619
- # @return void
620
- def parse_error(err, ctx)
621
- @parse_error_proc.call(err, ctx)
622
- end
623
298
 
624
- # @param new_proc [#call] A new callable for handling parse errors during execution
625
- def parse_error=(new_proc)
626
- @parse_error_proc = new_proc
627
- end
299
+ # @api private
300
+ attr_writer :connections
628
301
 
629
- # Get a unique identifier from this object
630
- # @param object [Any] An application object
631
- # @param type [GraphQL::BaseType] The current type definition
632
- # @param ctx [GraphQL::Query::Context] the context for the current query
633
- # @return [String] a unique identifier for `object` which clients can use to refetch it
634
- def id_from_object(object, type, ctx)
635
- if @id_from_object_proc.nil?
636
- raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
637
- else
638
- @id_from_object_proc.call(object, type, ctx)
302
+ # @return [GraphQL::Pagination::Connections] if installed
303
+ def connections
304
+ if defined?(@connections)
305
+ @connections
306
+ else
307
+ inherited_connections = find_inherited_value(:connections, nil)
308
+ # This schema is part of an inheritance chain which is using new connections,
309
+ # make a new instance, so we don't pollute the upstream one.
310
+ if inherited_connections
311
+ @connections = Pagination::Connections.new(schema: self)
312
+ else
313
+ nil
314
+ end
315
+ end
639
316
  end
640
- end
641
317
 
642
- # @param new_proc [#call] A new callable for generating unique IDs
643
- def id_from_object=(new_proc)
644
- @id_from_object_proc = new_proc
645
- end
646
-
647
- # Create schema with the result of an introspection query.
648
- # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
649
- # @return [GraphQL::Schema] the schema described by `input`
650
- def self.from_introspection(introspection_result)
651
- GraphQL::Schema::Loader.load(introspection_result)
652
- end
653
-
654
- # Create schema from an IDL schema or file containing an IDL definition.
655
- # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
656
- # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
657
- # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
658
- # @return [GraphQL::Schema] the schema described by `document`
659
- def self.from_definition(definition_or_path, default_resolve: BuildFromDefinition::DefaultResolve, parser: BuildFromDefinition::DefaultParser)
660
- # If the file ends in `.graphql`, treat it like a filepath
661
- definition = if definition_or_path.end_with?(".graphql")
662
- File.read(definition_or_path)
663
- else
664
- definition_or_path
665
- end
666
- GraphQL::Schema::BuildFromDefinition.from_definition(definition, default_resolve: default_resolve, parser: parser)
667
- end
668
-
669
- # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
670
- class InvalidDocumentError < Error; end;
671
-
672
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
673
- def lazy_method_name(obj)
674
- @lazy_methods.get(obj)
675
- end
676
-
677
- # @return [Boolean] True if this object should be lazily resolved
678
- def lazy?(obj)
679
- !!lazy_method_name(obj)
680
- end
681
-
682
- # Return the GraphQL IDL for the schema
683
- # @param context [Hash]
684
- # @param only [<#call(member, ctx)>]
685
- # @param except [<#call(member, ctx)>]
686
- # @return [String]
687
- def to_definition(only: nil, except: nil, context: {})
688
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
689
- end
690
-
691
- # Return the GraphQL::Language::Document IDL AST for the schema
692
- # @param context [Hash]
693
- # @param only [<#call(member, ctx)>]
694
- # @param except [<#call(member, ctx)>]
695
- # @return [GraphQL::Language::Document]
696
- def to_document(only: nil, except: nil, context: {})
697
- GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
698
- end
699
-
700
- # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
701
- # @param context [Hash]
702
- # @param only [<#call(member, ctx)>]
703
- # @param except [<#call(member, ctx)>]
704
- # @return [Hash] GraphQL result
705
- def as_json(only: nil, except: nil, context: {})
706
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
707
- end
708
-
709
- # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
710
- # @see {#as_json}
711
- # @return [String]
712
- def to_json(*args)
713
- JSON.pretty_generate(as_json(*args))
714
- end
715
-
716
- class << self
717
- extend Forwardable
718
- # For compatibility, these methods all:
719
- # - Cause the Schema instance to be created, if it hasn't been created yet
720
- # - Delegate to that instance
721
- # Eventually, the methods will be moved into this class, removing the need for the singleton.
722
- def_delegators :graphql_definition,
723
- # Schema structure
724
- :as_json, :to_json, :to_document, :to_definition, :ast_node,
725
- # Execution
726
- :execute, :multiplex,
727
- :static_validator, :introspection_system,
728
- :query_analyzers, :tracers, :instrumenters,
729
- :execution_strategy_for_operation,
730
- :validate, :multiplex_analyzers, :lazy?, :lazy_method_name, :after_lazy, :sync_lazy,
731
- # Configuration
732
- :analysis_engine, :analysis_engine=, :using_ast_analysis?, :interpreter?,
733
- :max_complexity=, :max_depth=,
734
- :error_bubbling=,
735
- :metadata,
736
- :default_mask,
737
- :default_filter, :redefine,
738
- :id_from_object_proc, :object_from_id_proc,
739
- :id_from_object=, :object_from_id=,
740
- :remove_handler,
741
- # Members
742
- :types, :get_fields, :find,
743
- :root_type_for_operation,
744
- :subscriptions,
745
- :union_memberships,
746
- :get_field, :root_types, :references_to, :type_from_ast,
747
- :possible_types,
748
- :disable_introspection_entry_points=,
749
- :disable_schema_introspection_entry_point=,
750
- :disable_type_introspection_entry_point=
751
-
752
- def graphql_definition
753
- @graphql_definition ||= to_graphql
754
- end
755
-
756
- def use(plugin, **options)
757
- own_plugins << [plugin, options]
318
+ def new_connections?
319
+ !!connections
758
320
  end
759
321
 
760
- def plugins
761
- find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
322
+ def query(new_query_object = nil)
323
+ if new_query_object
324
+ if @query_object
325
+ raise GraphQL::Error, "Second definition of `query(...)` (#{new_query_object.inspect}) is invalid, already configured with #{@query_object.inspect}"
326
+ else
327
+ @query_object = new_query_object
328
+ add_type_and_traverse(new_query_object, root: true)
329
+ nil
330
+ end
331
+ else
332
+ @query_object || find_inherited_value(:query)
333
+ end
762
334
  end
763
335
 
764
- def to_graphql
765
- schema_defn = self.new
766
- schema_defn.raise_definition_error = true
767
- schema_defn.query = query
768
- schema_defn.mutation = mutation
769
- schema_defn.subscription = subscription
770
- schema_defn.max_complexity = max_complexity
771
- schema_defn.error_bubbling = error_bubbling
772
- schema_defn.max_depth = max_depth
773
- schema_defn.default_max_page_size = default_max_page_size
774
- schema_defn.orphan_types = orphan_types
775
- schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
776
- schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
777
- schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
778
-
779
- prepped_dirs = {}
780
- directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
781
- schema_defn.directives = prepped_dirs
782
- schema_defn.introspection_namespace = introspection
783
- schema_defn.resolve_type = method(:resolve_type)
784
- schema_defn.object_from_id = method(:object_from_id)
785
- schema_defn.id_from_object = method(:id_from_object)
786
- schema_defn.type_error = method(:type_error)
787
- schema_defn.context_class = context_class
788
- schema_defn.cursor_encoder = cursor_encoder
789
- schema_defn.tracers.concat(tracers)
790
- schema_defn.query_analyzers.concat(query_analyzers)
791
-
792
- schema_defn.middleware.concat(all_middleware)
793
- schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
794
- schema_defn.query_execution_strategy = query_execution_strategy
795
- schema_defn.mutation_execution_strategy = mutation_execution_strategy
796
- schema_defn.subscription_execution_strategy = subscription_execution_strategy
797
- all_instrumenters.each do |step, insts|
798
- insts.each do |inst|
799
- schema_defn.instrumenters[step] << inst
336
+ def mutation(new_mutation_object = nil)
337
+ if new_mutation_object
338
+ if @mutation_object
339
+ raise GraphQL::Error, "Second definition of `mutation(...)` (#{new_mutation_object.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
340
+ else
341
+ @mutation_object = new_mutation_object
342
+ add_type_and_traverse(new_mutation_object, root: true)
343
+ nil
800
344
  end
345
+ else
346
+ @mutation_object || find_inherited_value(:mutation)
801
347
  end
802
- lazy_classes.each do |lazy_class, value_method|
803
- schema_defn.lazy_methods.set(lazy_class, value_method)
348
+ end
349
+
350
+ def subscription(new_subscription_object = nil)
351
+ if new_subscription_object
352
+ if @subscription_object
353
+ raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
354
+ else
355
+ @subscription_object = new_subscription_object
356
+ add_subscription_extension_if_necessary
357
+ add_type_and_traverse(new_subscription_object, root: true)
358
+ nil
359
+ end
360
+ else
361
+ @subscription_object || find_inherited_value(:subscription)
804
362
  end
805
- rescues.each do |err_class, handler|
806
- schema_defn.rescue_from(err_class, &handler)
363
+ end
364
+
365
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
366
+ # @return [GraphQL::ObjectType, nil]
367
+ def root_type_for_operation(operation)
368
+ case operation
369
+ when "query"
370
+ query
371
+ when "mutation"
372
+ mutation
373
+ when "subscription"
374
+ subscription
375
+ else
376
+ raise ArgumentError, "unknown operation type: #{operation}"
807
377
  end
378
+ end
808
379
 
809
- if plugins.any?
810
- schema_plugins = plugins
811
- # TODO don't depend on .define
812
- schema_defn = schema_defn.redefine do
813
- schema_plugins.each do |plugin, options|
814
- if options.any?
815
- use(plugin, **options)
816
- else
817
- use(plugin)
380
+ def root_types
381
+ @root_types
382
+ end
383
+
384
+ # @param type [Module] The type definition whose possible types you want to see
385
+ # @return [Hash<String, Module>] All possible types, if no `type` is given.
386
+ # @return [Array<Module>] Possible types for `type`, if it's given.
387
+ def possible_types(type = nil, context = GraphQL::Query::NullContext)
388
+ if type
389
+ # TODO duck-typing `.possible_types` would probably be nicer here
390
+ if type.kind.union?
391
+ type.possible_types(context: context)
392
+ else
393
+ stored_possible_types = own_possible_types[type.graphql_name]
394
+ visible_possible_types = if stored_possible_types && type.kind.interface?
395
+ stored_possible_types.select do |possible_type|
396
+ possible_type.interfaces(context).include?(type)
818
397
  end
398
+ else
399
+ stored_possible_types
819
400
  end
401
+ visible_possible_types ||
402
+ introspection_system.possible_types[type.graphql_name] ||
403
+ (
404
+ superclass.respond_to?(:possible_types) ?
405
+ superclass.possible_types(type, context) :
406
+ EMPTY_ARRAY
407
+ )
820
408
  end
409
+ else
410
+ find_inherited_value(:possible_types, EMPTY_HASH)
411
+ .merge(own_possible_types)
412
+ .merge(introspection_system.possible_types)
821
413
  end
822
- # Do this after `plugins` since Interpreter is a plugin
823
- if schema_defn.query_execution_strategy != GraphQL::Execution::Interpreter
824
- schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
414
+ end
415
+
416
+ def union_memberships(type = nil)
417
+ if type
418
+ own_um = own_union_memberships.fetch(type.graphql_name, EMPTY_ARRAY)
419
+ inherited_um = find_inherited_value(:union_memberships, EMPTY_HASH).fetch(type.graphql_name, EMPTY_ARRAY)
420
+ own_um + inherited_um
421
+ else
422
+ joined_um = own_union_memberships.dup
423
+ find_inherited_value(:union_memberhips, EMPTY_HASH).each do |k, v|
424
+ um = joined_um[k] ||= []
425
+ um.concat(v)
426
+ end
427
+ joined_um
825
428
  end
826
- schema_defn.send(:rebuild_artifacts)
429
+ end
827
430
 
828
- schema_defn
431
+ # @api private
432
+ # @see GraphQL::Dataloader
433
+ def dataloader_class
434
+ @dataloader_class || GraphQL::Dataloader::NullDataloader
829
435
  end
830
436
 
831
- def query(new_query_object = nil)
832
- if new_query_object
833
- @query_object = new_query_object
437
+ attr_writer :dataloader_class
438
+
439
+ def references_to(to_type = nil, from: nil)
440
+ @own_references_to ||= Hash.new { |h, k| h[k] = [] }
441
+ if to_type
442
+ if !to_type.is_a?(String)
443
+ to_type = to_type.graphql_name
444
+ end
445
+
446
+ if from
447
+ @own_references_to[to_type] << from
448
+ else
449
+ own_refs = @own_references_to[to_type]
450
+ inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
451
+ own_refs + inherited_refs
452
+ end
834
453
  else
835
- query_object = @query_object || find_inherited_value(:query)
836
- query_object.respond_to?(:graphql_definition) ? query_object.graphql_definition : query_object
454
+ # `@own_references_to` can be quite large for big schemas,
455
+ # and generally speaking, we won't inherit any values.
456
+ # So optimize the most common case -- don't create a duplicate Hash.
457
+ inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
458
+ if inherited_value.any?
459
+ inherited_value.merge(@own_references_to)
460
+ else
461
+ @own_references_to
462
+ end
837
463
  end
838
464
  end
839
465
 
840
- def mutation(new_mutation_object = nil)
841
- if new_mutation_object
842
- @mutation_object = new_mutation_object
466
+ def type_from_ast(ast_node, context: nil)
467
+ type_owner = context ? context.warden : self
468
+ GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
469
+ end
470
+
471
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
472
+ parent_type = case type_or_name
473
+ when LateBoundType
474
+ get_type(type_or_name.name, context)
475
+ when String
476
+ get_type(type_or_name, context)
477
+ when Module
478
+ type_or_name
843
479
  else
844
- mutation_object = @mutation_object || find_inherited_value(:mutation)
845
- mutation_object.respond_to?(:graphql_definition) ? mutation_object.graphql_definition : mutation_object
480
+ raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
846
481
  end
847
- end
848
482
 
849
- def subscription(new_subscription_object = nil)
850
- if new_subscription_object
851
- @subscription_object = new_subscription_object
483
+ if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
484
+ field
485
+ elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
486
+ entry_point_field
487
+ elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
488
+ dynamic_field
852
489
  else
853
- subscription_object = @subscription_object || find_inherited_value(:subscription)
854
- subscription_object.respond_to?(:graphql_definition) ? subscription_object.graphql_definition : subscription_object
490
+ nil
855
491
  end
856
492
  end
857
493
 
494
+ def get_fields(type, context = GraphQL::Query::NullContext)
495
+ type.fields(context)
496
+ end
497
+
858
498
  def introspection(new_introspection_namespace = nil)
859
499
  if new_introspection_namespace
860
500
  @introspection = new_introspection_namespace
501
+ # reset this cached value:
502
+ @introspection_system = nil
861
503
  else
862
504
  @introspection || find_inherited_value(:introspection)
863
505
  end
864
506
  end
865
507
 
508
+ def introspection_system
509
+ if !@introspection_system
510
+ @introspection_system = Schema::IntrospectionSystem.new(self)
511
+ @introspection_system.resolve_late_bindings
512
+ end
513
+ @introspection_system
514
+ end
515
+
866
516
  def cursor_encoder(new_encoder = nil)
867
517
  if new_encoder
868
518
  @cursor_encoder = new_encoder
@@ -878,6 +528,14 @@ module GraphQL
878
528
  end
879
529
  end
880
530
 
531
+ def default_page_size(new_default_page_size = nil)
532
+ if new_default_page_size
533
+ @default_page_size = new_default_page_size
534
+ else
535
+ @default_page_size || find_inherited_value(:default_page_size)
536
+ end
537
+ end
538
+
881
539
  def query_execution_strategy(new_query_execution_strategy = nil)
882
540
  if new_query_execution_strategy
883
541
  @query_execution_strategy = new_query_execution_strategy
@@ -902,14 +560,75 @@ module GraphQL
902
560
  end
903
561
  end
904
562
 
563
+ attr_writer :validate_timeout
564
+
565
+ def validate_timeout(new_validate_timeout = nil)
566
+ if new_validate_timeout
567
+ @validate_timeout = new_validate_timeout
568
+ elsif defined?(@validate_timeout)
569
+ @validate_timeout
570
+ else
571
+ find_inherited_value(:validate_timeout)
572
+ end
573
+ end
574
+
575
+ # Validate a query string according to this schema.
576
+ # @param string_or_document [String, GraphQL::Language::Nodes::Document]
577
+ # @return [Array<GraphQL::StaticValidation::Error >]
578
+ def validate(string_or_document, rules: nil, context: nil)
579
+ doc = if string_or_document.is_a?(String)
580
+ GraphQL.parse(string_or_document)
581
+ else
582
+ string_or_document
583
+ end
584
+ query = GraphQL::Query.new(self, document: doc, context: context)
585
+ validator_opts = { schema: self }
586
+ rules && (validator_opts[:rules] = rules)
587
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
588
+ res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
589
+ res[:errors]
590
+ end
591
+
592
+ attr_writer :validate_max_errors
593
+
594
+ def validate_max_errors(new_validate_max_errors = nil)
595
+ if new_validate_max_errors
596
+ @validate_max_errors = new_validate_max_errors
597
+ elsif defined?(@validate_max_errors)
598
+ @validate_max_errors
599
+ else
600
+ find_inherited_value(:validate_max_errors)
601
+ end
602
+ end
603
+
604
+ attr_writer :max_complexity
605
+
905
606
  def max_complexity(max_complexity = nil)
906
607
  if max_complexity
907
608
  @max_complexity = max_complexity
609
+ elsif defined?(@max_complexity)
610
+ @max_complexity
908
611
  else
909
- @max_complexity || find_inherited_value(:max_complexity)
612
+ find_inherited_value(:max_complexity)
910
613
  end
911
614
  end
912
615
 
616
+ attr_writer :analysis_engine
617
+
618
+ def analysis_engine
619
+ @analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
620
+ end
621
+
622
+ def using_ast_analysis?
623
+ true
624
+ end
625
+
626
+ def interpreter?
627
+ true
628
+ end
629
+
630
+ attr_writer :interpreter
631
+
913
632
  def error_bubbling(new_error_bubbling = nil)
914
633
  if !new_error_bubbling.nil?
915
634
  @error_bubbling = new_error_bubbling
@@ -918,24 +637,36 @@ module GraphQL
918
637
  end
919
638
  end
920
639
 
640
+ attr_writer :error_bubbling
641
+
642
+ attr_writer :max_depth
643
+
921
644
  def max_depth(new_max_depth = nil)
922
645
  if new_max_depth
923
646
  @max_depth = new_max_depth
647
+ elsif defined?(@max_depth)
648
+ @max_depth
924
649
  else
925
- @max_depth || find_inherited_value(:max_depth)
650
+ find_inherited_value(:max_depth)
926
651
  end
927
652
  end
928
653
 
929
654
  def disable_introspection_entry_points
930
655
  @disable_introspection_entry_points = true
656
+ # TODO: this clears the cache made in `def types`. But this is not a great solution.
657
+ @introspection_system = nil
931
658
  end
932
659
 
933
660
  def disable_schema_introspection_entry_point
934
661
  @disable_schema_introspection_entry_point = true
662
+ # TODO: this clears the cache made in `def types`. But this is not a great solution.
663
+ @introspection_system = nil
935
664
  end
936
665
 
937
666
  def disable_type_introspection_entry_point
938
667
  @disable_type_introspection_entry_point = true
668
+ # TODO: this clears the cache made in `def types`. But this is not a great solution.
669
+ @introspection_system = nil
939
670
  end
940
671
 
941
672
  def disable_introspection_entry_points?
@@ -964,6 +695,8 @@ module GraphQL
964
695
 
965
696
  def orphan_types(*new_orphan_types)
966
697
  if new_orphan_types.any?
698
+ new_orphan_types = new_orphan_types.flatten
699
+ add_type_and_traverse(new_orphan_types, root: false)
967
700
  own_orphan_types.concat(new_orphan_types.flatten)
968
701
  end
969
702
 
@@ -974,7 +707,15 @@ module GraphQL
974
707
  if superclass <= GraphQL::Schema
975
708
  superclass.default_execution_strategy
976
709
  else
977
- @default_execution_strategy ||= GraphQL::Execution::Execute
710
+ @default_execution_strategy ||= GraphQL::Execution::Interpreter
711
+ end
712
+ end
713
+
714
+ def default_analysis_engine
715
+ if superclass <= GraphQL::Schema
716
+ superclass.default_analysis_engine
717
+ else
718
+ @default_analysis_engine ||= GraphQL::Analysis::AST
978
719
  end
979
720
  end
980
721
 
@@ -988,12 +729,72 @@ module GraphQL
988
729
 
989
730
  def rescue_from(*err_classes, &handler_block)
990
731
  err_classes.each do |err_class|
991
- own_rescues[err_class] = handler_block
732
+ Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
733
+ end
734
+ end
735
+
736
+ NEW_HANDLER_HASH = ->(h, k) {
737
+ h[k] = {
738
+ class: k,
739
+ handler: nil,
740
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
741
+ }
742
+ }
743
+
744
+ def error_handlers
745
+ @error_handlers ||= {
746
+ class: nil,
747
+ handler: nil,
748
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
749
+ }
750
+ end
751
+
752
+ # @api private
753
+ def handle_or_reraise(context, err)
754
+ handler = Execution::Errors.find_handler_for(self, err.class)
755
+ if handler
756
+ obj = context[:current_object]
757
+ args = context[:current_arguments]
758
+ args = args && args.keyword_arguments
759
+ field = context[:current_field]
760
+ if obj.is_a?(GraphQL::Schema::Object)
761
+ obj = obj.object
762
+ end
763
+ handler[:handler].call(err, obj, args, context, field)
764
+ else
765
+ raise err
992
766
  end
993
767
  end
994
768
 
995
- def rescues
996
- find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
769
+ # rubocop:disable Lint/DuplicateMethods
770
+ module ResolveTypeWithType
771
+ def resolve_type(type, obj, ctx)
772
+ maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
773
+ type.resolve_type(obj, ctx)
774
+ else
775
+ super
776
+ end
777
+
778
+ after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
779
+ if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
780
+ resolved_type = resolve_type_result[0]
781
+ resolved_value = resolve_type_result[1]
782
+ else
783
+ resolved_type = resolve_type_result
784
+ resolved_value = obj
785
+ end
786
+
787
+ if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
788
+ if resolved_value
789
+ [resolved_type, resolved_value]
790
+ else
791
+ resolved_type
792
+ end
793
+ else
794
+ raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
795
+ end
796
+ end
797
+ end
997
798
  end
998
799
 
999
800
  def resolve_type(type, obj, ctx)
@@ -1003,6 +804,15 @@ module GraphQL
1003
804
  raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
1004
805
  end
1005
806
  end
807
+ # rubocop:enable Lint/DuplicateMethods
808
+
809
+ def inherited(child_class)
810
+ if self == GraphQL::Schema
811
+ child_class.directives(default_directives.values)
812
+ end
813
+ child_class.singleton_class.prepend(ResolveTypeWithType)
814
+ super
815
+ end
1006
816
 
1007
817
  def object_from_id(node_id, ctx)
1008
818
  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}`)"
@@ -1012,12 +822,21 @@ module GraphQL
1012
822
  raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
1013
823
  end
1014
824
 
1015
- def visible?(member, context)
1016
- call_on_type_class(member, :visible?, context, default: true)
825
+ def visible?(member, ctx)
826
+ member.visible?(ctx)
827
+ end
828
+
829
+ def accessible?(member, ctx)
830
+ member.accessible?(ctx)
1017
831
  end
1018
832
 
1019
- def accessible?(member, context)
1020
- call_on_type_class(member, :accessible?, context, default: true)
833
+ def schema_directive(dir_class, **options)
834
+ @own_schema_directives ||= []
835
+ Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
836
+ end
837
+
838
+ def schema_directives
839
+ Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
1021
840
  end
1022
841
 
1023
842
  # This hook is called when a client tries to access one or more
@@ -1067,49 +886,59 @@ module GraphQL
1067
886
  unauthorized_object(unauthorized_error)
1068
887
  end
1069
888
 
1070
- def type_error(type_err, ctx)
1071
- DefaultTypeError.call(type_err, ctx)
889
+ def type_error(type_error, ctx)
890
+ case type_error
891
+ when GraphQL::InvalidNullError
892
+ ctx.errors << type_error
893
+ when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
894
+ raise type_error
895
+ when GraphQL::IntegerDecodingError
896
+ nil
897
+ end
1072
898
  end
1073
899
 
1074
- attr_writer :error_handler
1075
-
1076
- # @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
1077
- def error_handler
1078
- @error_handler ||= GraphQL::Execution::Errors::NullErrorHandler
900
+ # A function to call when {#execute} receives an invalid query string
901
+ #
902
+ # The default is to add the error to `context.errors`
903
+ # @param err [GraphQL::ParseError] The error encountered during parsing
904
+ # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
905
+ # @return void
906
+ def parse_error(parse_err, ctx)
907
+ ctx.errors.push(parse_err)
1079
908
  end
1080
909
 
1081
910
  def lazy_resolve(lazy_class, value_method)
1082
- lazy_classes[lazy_class] = value_method
911
+ lazy_methods.set(lazy_class, value_method)
1083
912
  end
1084
913
 
1085
914
  def instrument(instrument_step, instrumenter, options = {})
1086
- step = if instrument_step == :field && options[:after_built_ins]
1087
- :field_after_built_ins
1088
- else
1089
- instrument_step
1090
- end
1091
-
1092
- own_instrumenters[step] << instrumenter
915
+ own_instrumenters[instrument_step] << instrumenter
1093
916
  end
1094
917
 
1095
- def directives(new_directives = nil)
1096
- if new_directives
1097
- new_directives.each {|d| directive(d) }
918
+ # Add several directives at once
919
+ # @param new_directives [Class]
920
+ def directives(*new_directives)
921
+ if new_directives.any?
922
+ new_directives.flatten.each { |d| directive(d) }
1098
923
  end
1099
924
 
1100
925
  find_inherited_value(:directives, default_directives).merge(own_directives)
1101
926
  end
1102
927
 
928
+ # Attach a single directive to this schema
929
+ # @param new_directive [Class]
930
+ # @return void
1103
931
  def directive(new_directive)
1104
- own_directives[new_directive.graphql_name] = new_directive
932
+ add_type_and_traverse(new_directive, root: false)
1105
933
  end
1106
934
 
1107
935
  def default_directives
1108
- {
1109
- "include" => GraphQL::Directive::IncludeDirective,
1110
- "skip" => GraphQL::Directive::SkipDirective,
1111
- "deprecated" => GraphQL::Directive::DeprecatedDirective,
1112
- }
936
+ @default_directives ||= {
937
+ "include" => GraphQL::Schema::Directive::Include,
938
+ "skip" => GraphQL::Schema::Directive::Skip,
939
+ "deprecated" => GraphQL::Schema::Directive::Deprecated,
940
+ "oneOf" => GraphQL::Schema::Directive::OneOf,
941
+ }.freeze
1113
942
  end
1114
943
 
1115
944
  def tracer(new_tracer)
@@ -1121,9 +950,6 @@ module GraphQL
1121
950
  end
1122
951
 
1123
952
  def query_analyzer(new_analyzer)
1124
- if new_analyzer == GraphQL::Authorization::Analyzer
1125
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1126
- end
1127
953
  own_query_analyzers << new_analyzer
1128
954
  end
1129
955
 
@@ -1131,14 +957,6 @@ module GraphQL
1131
957
  find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1132
958
  end
1133
959
 
1134
- def middleware(new_middleware = nil)
1135
- if new_middleware
1136
- own_middleware << new_middleware
1137
- else
1138
- graphql_definition.middleware
1139
- end
1140
- end
1141
-
1142
960
  def multiplex_analyzer(new_analyzer)
1143
961
  own_multiplex_analyzers << new_analyzer
1144
962
  end
@@ -1147,188 +965,251 @@ module GraphQL
1147
965
  find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1148
966
  end
1149
967
 
1150
- private
1151
-
1152
- def lazy_classes
1153
- @lazy_classes ||= {}
1154
- end
1155
-
1156
- def own_plugins
1157
- @own_plugins ||= []
1158
- end
1159
-
1160
- def own_rescues
1161
- @own_rescues ||= {}
968
+ def sanitized_printer(new_sanitized_printer = nil)
969
+ if new_sanitized_printer
970
+ @own_sanitized_printer = new_sanitized_printer
971
+ else
972
+ @own_sanitized_printer || GraphQL::Language::SanitizedPrinter
973
+ end
1162
974
  end
1163
975
 
1164
- def own_orphan_types
1165
- @own_orphan_types ||= []
976
+ # Execute a query on itself.
977
+ # @see {Query#initialize} for arguments.
978
+ # @return [Hash] query result, ready to be serialized as JSON
979
+ def execute(query_str = nil, **kwargs)
980
+ if query_str
981
+ kwargs[:query] = query_str
982
+ end
983
+ # Some of the query context _should_ be passed to the multiplex, too
984
+ multiplex_context = if (ctx = kwargs[:context])
985
+ {
986
+ backtrace: ctx[:backtrace],
987
+ tracers: ctx[:tracers],
988
+ dataloader: ctx[:dataloader],
989
+ }
990
+ else
991
+ {}
992
+ end
993
+ # Since we're running one query, don't run a multiplex-level complexity analyzer
994
+ all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
995
+ all_results[0]
1166
996
  end
1167
997
 
1168
- def own_directives
1169
- @own_directives ||= {}
998
+ # Execute several queries on itself, concurrently.
999
+ #
1000
+ # @example Run several queries at once
1001
+ # context = { ... }
1002
+ # queries = [
1003
+ # { query: params[:query_1], variables: params[:variables_1], context: context },
1004
+ # { query: params[:query_2], variables: params[:variables_2], context: context },
1005
+ # ]
1006
+ # results = MySchema.multiplex(queries)
1007
+ # render json: {
1008
+ # result_1: results[0],
1009
+ # result_2: results[1],
1010
+ # }
1011
+ #
1012
+ # @see {Query#initialize} for query keyword arguments
1013
+ # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
1014
+ # @param queries [Array<Hash>] Keyword arguments for each query
1015
+ # @param context [Hash] Multiplex-level context
1016
+ # @return [Array<Hash>] One result for each query in the input
1017
+ def multiplex(queries, **kwargs)
1018
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1170
1019
  end
1171
1020
 
1172
- def all_instrumenters
1173
- inherited_instrumenters = find_inherited_value(:all_instrumenters) || Hash.new { |h,k| h[k] = [] }
1021
+ def instrumenters
1022
+ inherited_instrumenters = find_inherited_value(:instrumenters) || Hash.new { |h,k| h[k] = [] }
1174
1023
  inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
1175
1024
  inherited + own
1176
1025
  end
1177
1026
  end
1178
1027
 
1179
- def own_instrumenters
1180
- @own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1028
+ # @api private
1029
+ def add_subscription_extension_if_necessary
1030
+ if !defined?(@subscription_extension_added) && subscription && self.subscriptions
1031
+ @subscription_extension_added = true
1032
+ subscription.all_field_definitions.each do |field|
1033
+ if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
1034
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1035
+ end
1036
+ end
1037
+ end
1181
1038
  end
1182
1039
 
1183
- def own_tracers
1184
- @own_tracers ||= []
1040
+ def query_stack_error(query, err)
1041
+ query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1185
1042
  end
1186
1043
 
1187
- def own_query_analyzers
1188
- @defined_query_analyzers ||= []
1044
+ # Call the given block at the right time, either:
1045
+ # - Right away, if `value` is not registered with `lazy_resolve`
1046
+ # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1047
+ # @api private
1048
+ def after_lazy(value, &block)
1049
+ if lazy?(value)
1050
+ GraphQL::Execution::Lazy.new do
1051
+ result = sync_lazy(value)
1052
+ # The returned result might also be lazy, so check it, too
1053
+ after_lazy(result, &block)
1054
+ end
1055
+ else
1056
+ yield(value) if block_given?
1057
+ end
1189
1058
  end
1190
1059
 
1191
- def all_middleware
1192
- find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1060
+ # Override this method to handle lazy objects in a custom way.
1061
+ # @param value [Object] an instance of a class registered with {.lazy_resolve}
1062
+ # @return [Object] A GraphQL-ready (non-lazy) object
1063
+ # @api private
1064
+ def sync_lazy(value)
1065
+ lazy_method = lazy_method_name(value)
1066
+ if lazy_method
1067
+ synced_value = value.public_send(lazy_method)
1068
+ sync_lazy(synced_value)
1069
+ else
1070
+ value
1071
+ end
1193
1072
  end
1194
1073
 
1195
- def own_middleware
1196
- @own_middleware ||= []
1074
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
1075
+ def lazy_method_name(obj)
1076
+ lazy_methods.get(obj)
1197
1077
  end
1198
1078
 
1199
- def own_multiplex_analyzers
1200
- @own_multiplex_analyzers ||= []
1079
+ # @return [Boolean] True if this object should be lazily resolved
1080
+ def lazy?(obj)
1081
+ !!lazy_method_name(obj)
1201
1082
  end
1202
1083
 
1203
- # Given this schema member, find the class-based definition object
1204
- # whose `method_name` should be treated as an application hook
1205
- # @see {.visible?}
1206
- # @see {.accessible?}
1207
- # @see {.authorized?}
1208
- def call_on_type_class(member, method_name, *args, default:)
1209
- member = if member.respond_to?(:metadata) && member.metadata
1210
- member.metadata[:type_class] || member
1084
+ # Return a lazy if any of `maybe_lazies` are lazy,
1085
+ # otherwise, call the block eagerly and return the result.
1086
+ # @param maybe_lazies [Array]
1087
+ # @api private
1088
+ def after_any_lazies(maybe_lazies)
1089
+ if maybe_lazies.any? { |l| lazy?(l) }
1090
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
1091
+ yield result
1092
+ end
1211
1093
  else
1212
- member
1094
+ yield maybe_lazies
1213
1095
  end
1096
+ end
1097
+
1098
+ private
1214
1099
 
1215
- if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
1216
- member = t
1100
+ # @param t [Module, Array<Module>]
1101
+ # @return [void]
1102
+ def add_type_and_traverse(t, root:)
1103
+ if root
1104
+ @root_types ||= []
1105
+ @root_types << t
1217
1106
  end
1107
+ new_types = Array(t)
1108
+ addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1109
+ addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
1110
+ if (prev_entry = own_types[name])
1111
+ prev_entries = case prev_entry
1112
+ when Array
1113
+ prev_entry
1114
+ when Module
1115
+ own_types[name] = [prev_entry]
1116
+ else
1117
+ raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
1118
+ end
1218
1119
 
1219
- if member.respond_to?(method_name)
1220
- member.public_send(method_name, *args)
1221
- else
1222
- default
1120
+ case types_entry
1121
+ when Array
1122
+ prev_entries.concat(types_entry)
1123
+ prev_entries.uniq! # in case any are being re-visited
1124
+ when Module
1125
+ if !prev_entries.include?(types_entry)
1126
+ prev_entries << types_entry
1127
+ end
1128
+ else
1129
+ raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
1130
+ end
1131
+ else
1132
+ if types_entry.is_a?(Array)
1133
+ types_entry.uniq!
1134
+ end
1135
+ own_types[name] = types_entry
1136
+ end
1223
1137
  end
1224
- end
1225
- end
1226
1138
 
1139
+ own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1140
+ own_union_memberships.merge!(addition.union_memberships)
1227
1141
 
1228
- def self.inherited(child_class)
1229
- child_class.singleton_class.class_eval do
1230
- prepend(MethodWrappers)
1231
- end
1232
- end
1142
+ addition.references.each { |thing, pointers|
1143
+ pointers.each { |pointer| references_to(thing, from: pointer) }
1144
+ }
1145
+
1146
+ addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
1233
1147
 
1234
- module MethodWrappers
1235
- # Wrap the user-provided resolve-type in a correctness check
1236
- def resolve_type(type, obj, ctx = :__undefined__)
1237
- graphql_definition.check_resolved_type(type, obj, ctx) do |ok_type, ok_obj, ok_ctx|
1238
- super(ok_type, ok_obj, ok_ctx)
1148
+ addition.arguments_with_default_values.each do |arg|
1149
+ arg.validate_default_value
1239
1150
  end
1240
1151
  end
1241
- end
1242
1152
 
1243
- # Call the given block at the right time, either:
1244
- # - Right away, if `value` is not registered with `lazy_resolve`
1245
- # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1246
- # @api private
1247
- def after_lazy(value)
1248
- if lazy?(value)
1249
- GraphQL::Execution::Lazy.new do
1250
- result = sync_lazy(value)
1251
- # The returned result might also be lazy, so check it, too
1252
- after_lazy(result) do |final_result|
1253
- yield(final_result) if block_given?
1153
+ def lazy_methods
1154
+ if !defined?(@lazy_methods)
1155
+ if inherited_map = find_inherited_value(:lazy_methods)
1156
+ # this isn't _completely_ inherited :S (Things added after `dup` won't work)
1157
+ @lazy_methods = inherited_map.dup
1158
+ else
1159
+ @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1160
+ @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1161
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1254
1162
  end
1255
1163
  end
1256
- else
1257
- yield(value) if block_given?
1164
+ @lazy_methods
1258
1165
  end
1259
- end
1260
1166
 
1261
- # Override this method to handle lazy objects in a custom way.
1262
- # @param value [Object] an instance of a class registered with {.lazy_resolve}
1263
- # @param ctx [GraphQL::Query::Context] the context for this query
1264
- # @return [Object] A GraphQL-ready (non-lazy) object
1265
- def self.sync_lazy(value)
1266
- if block_given?
1267
- # This was already hit by the instance, just give it back
1268
- yield(value)
1269
- else
1270
- # This was called directly on the class, hit the instance
1271
- # which has the lazy method map
1272
- self.graphql_definition.sync_lazy(value)
1167
+ def own_types
1168
+ @own_types ||= {}
1273
1169
  end
1274
- end
1275
1170
 
1276
- # @see Schema.sync_lazy for a hook to override
1277
- # @api private
1278
- def sync_lazy(value)
1279
- self.class.sync_lazy(value) { |v|
1280
- lazy_method = lazy_method_name(v)
1281
- if lazy_method
1282
- synced_value = value.public_send(lazy_method)
1283
- sync_lazy(synced_value)
1284
- else
1285
- v
1286
- end
1287
- }
1288
- end
1171
+ def non_introspection_types
1172
+ find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
1173
+ end
1289
1174
 
1290
- protected
1175
+ def own_plugins
1176
+ @own_plugins ||= []
1177
+ end
1291
1178
 
1292
- def rescues?
1293
- !!@rescue_middleware
1294
- end
1179
+ def own_orphan_types
1180
+ @own_orphan_types ||= []
1181
+ end
1295
1182
 
1296
- # Lazily create a middleware and add it to the schema
1297
- # (Don't add it if it's not used)
1298
- def rescue_middleware
1299
- @rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
1300
- end
1183
+ def own_possible_types
1184
+ @own_possible_types ||= {}
1185
+ end
1301
1186
 
1302
- private
1303
-
1304
- def rebuild_artifacts
1305
- if @rebuilding_artifacts
1306
- 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."
1307
- else
1308
- @rebuilding_artifacts = true
1309
- @introspection_system = Schema::IntrospectionSystem.new(self)
1310
- traversal = Traversal.new(self)
1311
- @types = traversal.type_map
1312
- @root_types = [query, mutation, subscription]
1313
- @instrumented_field_map = traversal.instrumented_field_map
1314
- @type_reference_map = traversal.type_reference_map
1315
- @union_memberships = traversal.union_memberships
1316
- @find_cache = {}
1317
- @finder = Finder.new(self)
1318
- end
1319
- ensure
1320
- @rebuilding_artifacts = false
1321
- end
1187
+ def own_union_memberships
1188
+ @own_union_memberships ||= {}
1189
+ end
1322
1190
 
1323
- class CyclicalDefinitionError < GraphQL::Error
1324
- end
1191
+ def own_directives
1192
+ @own_directives ||= {}
1193
+ end
1194
+
1195
+ def own_instrumenters
1196
+ @own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1197
+ end
1325
1198
 
1326
- def with_definition_error_check
1327
- if @definition_error
1328
- raise @definition_error
1329
- else
1330
- yield
1199
+ def own_tracers
1200
+ @own_tracers ||= []
1201
+ end
1202
+
1203
+ def own_query_analyzers
1204
+ @defined_query_analyzers ||= []
1205
+ end
1206
+
1207
+ def own_multiplex_analyzers
1208
+ @own_multiplex_analyzers ||= []
1331
1209
  end
1332
1210
  end
1211
+
1212
+ # Install these here so that subclasses will also install it.
1213
+ self.connections = GraphQL::Pagination::Connections.new(schema: self)
1333
1214
  end
1334
1215
  end