graphql_cody 1.13.0

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