graphql_cody 1.13.0

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