graphql 1.9.18 → 1.13.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +21 -10
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +44 -7
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +63 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +2 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  28. data/lib/generators/graphql/templates/base_object.erb +2 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +22 -27
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/analyze_query.rb +7 -0
  49. data/lib/graphql/analysis/ast/field_usage.rb +29 -2
  50. data/lib/graphql/analysis/ast/query_complexity.rb +174 -67
  51. data/lib/graphql/analysis/ast/visitor.rb +16 -7
  52. data/lib/graphql/analysis/ast.rb +21 -11
  53. data/lib/graphql/argument.rb +8 -36
  54. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  55. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  56. data/lib/graphql/backtrace/table.rb +44 -5
  57. data/lib/graphql/backtrace/traced_error.rb +0 -1
  58. data/lib/graphql/backtrace/tracer.rb +40 -9
  59. data/lib/graphql/backtrace.rb +28 -19
  60. data/lib/graphql/backwards_compatibility.rb +2 -1
  61. data/lib/graphql/base_type.rb +10 -4
  62. data/lib/graphql/boolean_type.rb +1 -1
  63. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  64. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  65. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  66. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  67. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  68. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  69. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  70. data/lib/graphql/dataloader/request.rb +19 -0
  71. data/lib/graphql/dataloader/request_all.rb +19 -0
  72. data/lib/graphql/dataloader/source.rb +155 -0
  73. data/lib/graphql/dataloader.rb +308 -0
  74. data/lib/graphql/date_encoding_error.rb +16 -0
  75. data/lib/graphql/define/assign_enum_value.rb +1 -1
  76. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  77. data/lib/graphql/define/assign_object_field.rb +1 -1
  78. data/lib/graphql/define/defined_object_proxy.rb +5 -8
  79. data/lib/graphql/define/instance_definable.rb +60 -110
  80. data/lib/graphql/define/type_definer.rb +5 -5
  81. data/lib/graphql/deprecated_dsl.rb +18 -5
  82. data/lib/graphql/deprecation.rb +9 -0
  83. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  84. data/lib/graphql/directive/include_directive.rb +1 -1
  85. data/lib/graphql/directive/skip_directive.rb +1 -1
  86. data/lib/graphql/directive.rb +9 -6
  87. data/lib/graphql/enum_type.rb +14 -74
  88. data/lib/graphql/execution/directive_checks.rb +2 -2
  89. data/lib/graphql/execution/errors.rb +110 -8
  90. data/lib/graphql/execution/execute.rb +8 -1
  91. data/lib/graphql/execution/instrumentation.rb +1 -1
  92. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  93. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  94. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  95. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  96. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  97. data/lib/graphql/execution/interpreter/runtime.rb +721 -386
  98. data/lib/graphql/execution/interpreter.rb +42 -19
  99. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  100. data/lib/graphql/execution/lazy.rb +5 -1
  101. data/lib/graphql/execution/lookahead.rb +39 -114
  102. data/lib/graphql/execution/multiplex.rb +50 -25
  103. data/lib/graphql/field.rb +15 -119
  104. data/lib/graphql/filter.rb +1 -1
  105. data/lib/graphql/float_type.rb +1 -1
  106. data/lib/graphql/function.rb +5 -30
  107. data/lib/graphql/id_type.rb +1 -1
  108. data/lib/graphql/input_object_type.rb +9 -25
  109. data/lib/graphql/int_type.rb +1 -1
  110. data/lib/graphql/integer_decoding_error.rb +17 -0
  111. data/lib/graphql/integer_encoding_error.rb +18 -2
  112. data/lib/graphql/interface_type.rb +10 -24
  113. data/lib/graphql/internal_representation/document.rb +2 -2
  114. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  115. data/lib/graphql/internal_representation/scope.rb +2 -2
  116. data/lib/graphql/internal_representation/visit.rb +2 -2
  117. data/lib/graphql/introspection/base_object.rb +2 -5
  118. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  119. data/lib/graphql/introspection/directive_type.rb +12 -6
  120. data/lib/graphql/introspection/entry_points.rb +9 -9
  121. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  122. data/lib/graphql/introspection/field_type.rb +9 -5
  123. data/lib/graphql/introspection/input_value_type.rb +41 -11
  124. data/lib/graphql/introspection/introspection_query.rb +6 -92
  125. data/lib/graphql/introspection/schema_type.rb +12 -12
  126. data/lib/graphql/introspection/type_type.rb +27 -17
  127. data/lib/graphql/introspection.rb +99 -0
  128. data/lib/graphql/invalid_null_error.rb +18 -0
  129. data/lib/graphql/language/block_string.rb +20 -5
  130. data/lib/graphql/language/cache.rb +37 -0
  131. data/lib/graphql/language/definition_slice.rb +21 -10
  132. data/lib/graphql/language/document_from_schema_definition.rb +116 -63
  133. data/lib/graphql/language/lexer.rb +53 -27
  134. data/lib/graphql/language/lexer.rl +5 -3
  135. data/lib/graphql/language/nodes.rb +67 -93
  136. data/lib/graphql/language/parser.rb +929 -896
  137. data/lib/graphql/language/parser.y +125 -102
  138. data/lib/graphql/language/printer.rb +11 -2
  139. data/lib/graphql/language/sanitized_printer.rb +222 -0
  140. data/lib/graphql/language/token.rb +0 -4
  141. data/lib/graphql/language/visitor.rb +2 -2
  142. data/lib/graphql/language.rb +3 -1
  143. data/lib/graphql/name_validator.rb +2 -7
  144. data/lib/graphql/non_null_type.rb +0 -10
  145. data/lib/graphql/object_type.rb +47 -58
  146. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  147. data/lib/graphql/pagination/array_connection.rb +77 -0
  148. data/lib/graphql/pagination/connection.rb +226 -0
  149. data/lib/graphql/pagination/connections.rb +160 -0
  150. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  151. data/lib/graphql/pagination/relation_connection.rb +226 -0
  152. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  153. data/lib/graphql/pagination.rb +6 -0
  154. data/lib/graphql/parse_error.rb +0 -1
  155. data/lib/graphql/query/arguments.rb +6 -4
  156. data/lib/graphql/query/arguments_cache.rb +1 -2
  157. data/lib/graphql/query/context.rb +52 -7
  158. data/lib/graphql/query/executor.rb +0 -1
  159. data/lib/graphql/query/fingerprint.rb +26 -0
  160. data/lib/graphql/query/input_validation_result.rb +32 -6
  161. data/lib/graphql/query/literal_input.rb +31 -11
  162. data/lib/graphql/query/null_context.rb +24 -8
  163. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  164. data/lib/graphql/query/serial_execution.rb +1 -0
  165. data/lib/graphql/query/validation_pipeline.rb +6 -4
  166. data/lib/graphql/query/variable_validation_error.rb +3 -3
  167. data/lib/graphql/query/variables.rb +50 -10
  168. data/lib/graphql/query.rb +77 -18
  169. data/lib/graphql/railtie.rb +9 -1
  170. data/lib/graphql/rake_task/validate.rb +3 -0
  171. data/lib/graphql/rake_task.rb +12 -9
  172. data/lib/graphql/relay/array_connection.rb +10 -12
  173. data/lib/graphql/relay/base_connection.rb +30 -13
  174. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  175. data/lib/graphql/relay/connection_type.rb +18 -4
  176. data/lib/graphql/relay/edge_type.rb +1 -0
  177. data/lib/graphql/relay/edges_instrumentation.rb +1 -2
  178. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  179. data/lib/graphql/relay/mutation.rb +3 -87
  180. data/lib/graphql/relay/node.rb +3 -0
  181. data/lib/graphql/relay/page_info.rb +1 -1
  182. data/lib/graphql/relay/range_add.rb +27 -9
  183. data/lib/graphql/relay/relation_connection.rb +8 -10
  184. data/lib/graphql/relay/type_extensions.rb +2 -0
  185. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  186. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  187. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  188. data/lib/graphql/rubocop.rb +4 -0
  189. data/lib/graphql/scalar_type.rb +18 -60
  190. data/lib/graphql/schema/addition.rb +247 -0
  191. data/lib/graphql/schema/argument.rb +274 -18
  192. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  193. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  194. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  195. data/lib/graphql/schema/build_from_definition.rb +320 -219
  196. data/lib/graphql/schema/built_in_types.rb +5 -5
  197. data/lib/graphql/schema/default_type_error.rb +2 -0
  198. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  199. data/lib/graphql/schema/directive/feature.rb +1 -1
  200. data/lib/graphql/schema/directive/flagged.rb +57 -0
  201. data/lib/graphql/schema/directive/include.rb +2 -2
  202. data/lib/graphql/schema/directive/skip.rb +2 -2
  203. data/lib/graphql/schema/directive/transform.rb +14 -2
  204. data/lib/graphql/schema/directive.rb +130 -6
  205. data/lib/graphql/schema/enum.rb +121 -12
  206. data/lib/graphql/schema/enum_value.rb +24 -7
  207. data/lib/graphql/schema/field/connection_extension.rb +46 -20
  208. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  209. data/lib/graphql/schema/field.rb +465 -181
  210. data/lib/graphql/schema/field_extension.rb +89 -2
  211. data/lib/graphql/schema/find_inherited_value.rb +17 -1
  212. data/lib/graphql/schema/finder.rb +16 -14
  213. data/lib/graphql/schema/input_object.rb +172 -37
  214. data/lib/graphql/schema/interface.rb +39 -25
  215. data/lib/graphql/schema/introspection_system.rb +106 -38
  216. data/lib/graphql/schema/late_bound_type.rb +3 -2
  217. data/lib/graphql/schema/list.rb +65 -1
  218. data/lib/graphql/schema/loader.rb +145 -102
  219. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  220. data/lib/graphql/schema/member/base_dsl_methods.rb +34 -28
  221. data/lib/graphql/schema/member/build_type.rb +19 -8
  222. data/lib/graphql/schema/member/cached_graphql_definition.rb +34 -2
  223. data/lib/graphql/schema/member/has_arguments.rb +206 -13
  224. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  225. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  226. data/lib/graphql/schema/member/has_directives.rb +98 -0
  227. data/lib/graphql/schema/member/has_fields.rb +97 -32
  228. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  229. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  230. data/lib/graphql/schema/member/has_validators.rb +31 -0
  231. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  232. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  233. data/lib/graphql/schema/member/validates_input.rb +33 -0
  234. data/lib/graphql/schema/member.rb +11 -0
  235. data/lib/graphql/schema/middleware_chain.rb +1 -1
  236. data/lib/graphql/schema/mutation.rb +4 -0
  237. data/lib/graphql/schema/non_null.rb +37 -1
  238. data/lib/graphql/schema/object.rb +51 -38
  239. data/lib/graphql/schema/possible_types.rb +9 -4
  240. data/lib/graphql/schema/printer.rb +16 -35
  241. data/lib/graphql/schema/relay_classic_mutation.rb +40 -4
  242. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  243. data/lib/graphql/schema/resolver.rb +133 -79
  244. data/lib/graphql/schema/scalar.rb +43 -3
  245. data/lib/graphql/schema/subscription.rb +57 -21
  246. data/lib/graphql/schema/timeout.rb +29 -15
  247. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  248. data/lib/graphql/schema/traversal.rb +2 -2
  249. data/lib/graphql/schema/type_expression.rb +21 -13
  250. data/lib/graphql/schema/type_membership.rb +19 -5
  251. data/lib/graphql/schema/union.rb +44 -3
  252. data/lib/graphql/schema/unique_within_type.rb +1 -2
  253. data/lib/graphql/schema/validation.rb +14 -4
  254. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  255. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  256. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  257. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  258. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  259. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  260. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  261. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  262. data/lib/graphql/schema/validator.rb +171 -0
  263. data/lib/graphql/schema/warden.rb +193 -34
  264. data/lib/graphql/schema.rb +882 -247
  265. data/lib/graphql/static_validation/all_rules.rb +2 -0
  266. data/lib/graphql/static_validation/base_visitor.rb +17 -10
  267. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  268. data/lib/graphql/static_validation/error.rb +3 -1
  269. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  270. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  271. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  272. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  273. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  274. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  275. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -2
  276. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  277. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  278. data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
  279. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  280. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  281. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  282. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  283. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  284. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  285. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  286. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  287. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  288. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  289. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  290. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  291. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  292. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  293. data/lib/graphql/static_validation/type_stack.rb +2 -2
  294. data/lib/graphql/static_validation/validation_context.rb +13 -3
  295. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  296. data/lib/graphql/static_validation/validator.rb +43 -9
  297. data/lib/graphql/static_validation.rb +1 -0
  298. data/lib/graphql/string_encoding_error.rb +13 -3
  299. data/lib/graphql/string_type.rb +1 -1
  300. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
  301. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  302. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  303. data/lib/graphql/subscriptions/event.rb +84 -30
  304. data/lib/graphql/subscriptions/instrumentation.rb +10 -6
  305. data/lib/graphql/subscriptions/serialize.rb +53 -6
  306. data/lib/graphql/subscriptions/subscription_root.rb +15 -5
  307. data/lib/graphql/subscriptions.rb +117 -49
  308. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  309. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  310. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  311. data/lib/graphql/tracing/data_dog_tracing.rb +32 -15
  312. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  313. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  314. data/lib/graphql/tracing/platform_tracing.rb +66 -10
  315. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  316. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  317. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  318. data/lib/graphql/tracing/skylight_tracing.rb +9 -1
  319. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  320. data/lib/graphql/tracing.rb +15 -35
  321. data/lib/graphql/types/big_int.rb +5 -1
  322. data/lib/graphql/types/int.rb +10 -3
  323. data/lib/graphql/types/iso_8601_date.rb +16 -8
  324. data/lib/graphql/types/iso_8601_date_time.rb +32 -10
  325. data/lib/graphql/types/relay/base_connection.rb +6 -88
  326. data/lib/graphql/types/relay/base_edge.rb +2 -34
  327. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  328. data/lib/graphql/types/relay/default_relay.rb +31 -0
  329. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  330. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  331. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  332. data/lib/graphql/types/relay/node.rb +2 -4
  333. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  334. data/lib/graphql/types/relay/node_field.rb +3 -22
  335. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  336. data/lib/graphql/types/relay/page_info.rb +2 -14
  337. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  338. data/lib/graphql/types/relay.rb +11 -3
  339. data/lib/graphql/types/string.rb +8 -2
  340. data/lib/graphql/unauthorized_error.rb +2 -2
  341. data/lib/graphql/union_type.rb +5 -25
  342. data/lib/graphql/unresolved_type_error.rb +2 -2
  343. data/lib/graphql/upgrader/member.rb +1 -0
  344. data/lib/graphql/upgrader/schema.rb +1 -0
  345. data/lib/graphql/version.rb +1 -1
  346. data/lib/graphql.rb +87 -31
  347. data/readme.md +3 -6
  348. metadata +126 -124
  349. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  350. data/lib/graphql/literal_validation_error.rb +0 -6
  351. data/lib/graphql/types/relay/base_field.rb +0 -22
  352. data/lib/graphql/types/relay/base_interface.rb +0 -29
  353. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -18,16 +18,18 @@ module GraphQL
18
18
  # @param new_name [String]
19
19
  # @return [String]
20
20
  def graphql_name(new_name = nil)
21
- case
22
- when new_name
21
+ if new_name
22
+ GraphQL::NameValidator.validate!(new_name)
23
23
  @graphql_name = new_name
24
- when overridden = overridden_graphql_name
25
- overridden
26
24
  else
27
- default_graphql_name
25
+ overridden_graphql_name || default_graphql_name
28
26
  end
29
27
  end
30
28
 
29
+ def overridden_graphql_name
30
+ defined?(@graphql_name) ? @graphql_name : nil
31
+ end
32
+
31
33
  # Just a convenience method to point out that people should use graphql_name instead
32
34
  def name(new_name = nil)
33
35
  return super() if new_name.nil?
@@ -45,8 +47,23 @@ module GraphQL
45
47
  def description(new_description = nil)
46
48
  if new_description
47
49
  @description = new_description
50
+ elsif defined?(@description)
51
+ @description
48
52
  else
49
- @description || find_inherited_value(:description)
53
+ nil
54
+ end
55
+ end
56
+
57
+ # This pushes some configurations _down_ the inheritance tree,
58
+ # in order to prevent repetitive lookups at runtime.
59
+ module ConfigurationExtension
60
+ def inherited(child_class)
61
+ child_class.introspection(introspection)
62
+ child_class.description(description)
63
+ if overridden_graphql_name
64
+ child_class.graphql_name(overridden_graphql_name)
65
+ end
66
+ super
50
67
  end
51
68
  end
52
69
 
@@ -54,8 +71,10 @@ module GraphQL
54
71
  def introspection(new_introspection = nil)
55
72
  if !new_introspection.nil?
56
73
  @introspection = new_introspection
74
+ elsif defined?(@introspection)
75
+ @introspection
57
76
  else
58
- @introspection || find_inherited_value(:introspection, false)
77
+ false
59
78
  end
60
79
  end
61
80
 
@@ -68,8 +87,11 @@ module GraphQL
68
87
  def mutation(mutation_class = nil)
69
88
  if mutation_class
70
89
  @mutation = mutation_class
90
+ elsif defined?(@mutation)
91
+ @mutation
92
+ else
93
+ nil
71
94
  end
72
- @mutation
73
95
  end
74
96
 
75
97
  # @return [GraphQL::BaseType] Convert this type to a legacy-style object.
@@ -79,10 +101,6 @@ module GraphQL
79
101
 
80
102
  alias :unwrap :itself
81
103
 
82
- def overridden_graphql_name
83
- @graphql_name || find_inherited_value(:overridden_graphql_name)
84
- end
85
-
86
104
  # Creates the default name for a schema member.
87
105
  # The default name is the Ruby constant name,
88
106
  # without any namespaces and with any `-Type` suffix removed
@@ -90,32 +108,20 @@ module GraphQL
90
108
  @default_graphql_name ||= begin
91
109
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
92
110
 
93
- name.split("::").last.sub(/Type\Z/, "")
111
+ -name.split("::").last.sub(/Type\Z/, "")
94
112
  end
95
113
  end
96
114
 
97
115
  def visible?(context)
98
- if @mutation
99
- @mutation.visible?(context)
100
- else
101
- true
102
- end
116
+ true
103
117
  end
104
118
 
105
119
  def accessible?(context)
106
- if @mutation
107
- @mutation.accessible?(context)
108
- else
109
- true
110
- end
120
+ true
111
121
  end
112
122
 
113
123
  def authorized?(object, context)
114
- if @mutation
115
- @mutation.authorized?(object, context)
116
- else
117
- true
118
- end
124
+ true
119
125
  end
120
126
  end
121
127
  end
@@ -56,28 +56,32 @@ module GraphQL
56
56
  parse_type(type_expr.first, null: false)
57
57
  when 2
58
58
  inner_type, nullable_option = type_expr
59
- if nullable_option.keys != [:null] || nullable_option.values != [true]
59
+ if nullable_option.keys != [:null] || (nullable_option[:null] != true && nullable_option[:null] != false)
60
60
  raise ArgumentError, LIST_TYPE_ERROR
61
61
  end
62
62
  list_type = true
63
- parse_type(inner_type, null: true)
63
+ parse_type(inner_type, null: nullable_option[:null])
64
64
  else
65
65
  raise ArgumentError, LIST_TYPE_ERROR
66
66
  end
67
+ when GraphQL::Schema::NonNull, GraphQL::Schema::List
68
+ type_expr
67
69
  when Module
68
70
  # This is a way to check that it's the right kind of module:
69
71
  if type_expr.respond_to?(:graphql_definition)
70
72
  type_expr
71
73
  else
72
- # Eg `String` => GraphQL::STRING_TYPE
74
+ # Eg `String` => GraphQL::Types::String
73
75
  parse_type(type_expr.name, null: true)
74
76
  end
77
+ when Proc
78
+ parse_type(type_expr.call, null: true)
75
79
  when false
76
80
  raise ArgumentError, "Received `false` instead of a type, maybe a `!` should be replaced with `null: true` (for fields) or `required: true` (for arguments)"
77
81
  end
78
82
 
79
83
  if return_type.nil?
80
- raise "Unexpected type input: #{type_expr} (#{type_expr.class})"
84
+ raise "Unexpected type input: #{type_expr.inspect} (#{type_expr.class})"
81
85
  end
82
86
 
83
87
  # Apply list_type first, that way the
@@ -116,6 +120,7 @@ module GraphQL
116
120
  end
117
121
 
118
122
  def camelize(string)
123
+ return string if string == '_'
119
124
  return string unless string.include?("_")
120
125
  camelized = string.split('_').map(&:capitalize).join
121
126
  camelized[0] = camelized[0].downcase
@@ -158,10 +163,16 @@ module GraphQL
158
163
  end
159
164
 
160
165
  def underscore(string)
161
- string
162
- .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
163
- .gsub(/([a-z\d])([A-Z])/,'\1_\2') # someThing -> some_Thing
164
- .downcase
166
+ if string.match?(/\A[a-z_]+\Z/)
167
+ return string
168
+ end
169
+ string2 = string.dup
170
+
171
+ string2.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
172
+ string2.gsub!(/([a-z\d])([A-Z])/,'\1_\2') # someThing -> some_Thing
173
+ string2.downcase!
174
+
175
+ string2
165
176
  end
166
177
  end
167
178
  end
@@ -11,8 +11,29 @@ module GraphQL
11
11
  # A cached result of {.to_graphql}.
12
12
  # It's cached here so that user-overridden {.to_graphql} implementations
13
13
  # are also cached
14
- def graphql_definition
15
- @graphql_definition ||= to_graphql
14
+ def graphql_definition(silence_deprecation_warning: false)
15
+ @graphql_definition ||= begin
16
+ unless silence_deprecation_warning
17
+ message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Remove `.graphql_definition` to use a class-based definition instead."
18
+ caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
19
+ GraphQL::Deprecation.warn(message + caller_message)
20
+ end
21
+ deprecated_to_graphql
22
+ end
23
+ end
24
+
25
+ def deprecated_to_graphql
26
+ case method(:to_graphql).arity
27
+ when 0
28
+ to_graphql
29
+ else
30
+ to_graphql(silence_deprecation_warning: true)
31
+ end
32
+ end
33
+
34
+ # This is for a common interface with .define-based types
35
+ def type_class
36
+ self
16
37
  end
17
38
 
18
39
  # Wipe out the cached graphql_definition so that `.to_graphql` will be called again.
@@ -20,6 +41,17 @@ module GraphQL
20
41
  super
21
42
  @graphql_definition = nil
22
43
  end
44
+
45
+ module DeprecatedToGraphQL
46
+ def to_graphql(silence_deprecation_warning: false)
47
+ unless silence_deprecation_warning
48
+ message = "Legacy `.to_graphql` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Remove `.to_graphql` to use a class-based definition instead."
49
+ caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
50
+ GraphQL::Deprecation.warn(message + caller_message)
51
+ end
52
+ super()
53
+ end
54
+ end
23
55
  end
24
56
  end
25
57
  end
@@ -37,24 +37,117 @@ module GraphQL
37
37
  end
38
38
  arg_defn = self.argument_class.new(*args, **kwargs, &block)
39
39
  add_argument(arg_defn)
40
+
41
+ if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
42
+ method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
43
+ "self."
44
+ elsif self < GraphQL::Schema::Resolver
45
+ ""
46
+ else
47
+ raise "Unexpected argument owner: #{self}"
48
+ end
49
+ if loads && arg_defn.type.list?
50
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
51
+ def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
52
+ argument = get_argument("#{arg_defn.graphql_name}")
53
+ (context || self.context).schema.after_lazy(values) do |values2|
54
+ GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
55
+ end
56
+ end
57
+ RUBY
58
+ elsif loads
59
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
60
+ def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
61
+ argument = get_argument("#{arg_defn.graphql_name}")
62
+ load_application_object(argument, value, context || self.context)
63
+ end
64
+ RUBY
65
+ else
66
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
67
+ def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
68
+ value
69
+ end
70
+ RUBY
71
+ end
72
+ end
73
+ arg_defn
40
74
  end
41
75
 
42
76
  # Register this argument with the class.
43
77
  # @param arg_defn [GraphQL::Schema::Argument]
44
78
  # @return [GraphQL::Schema::Argument]
45
79
  def add_argument(arg_defn)
46
- own_arguments[arg_defn.name] = arg_defn
80
+ @own_arguments ||= {}
81
+ prev_defn = own_arguments[arg_defn.name]
82
+ case prev_defn
83
+ when nil
84
+ own_arguments[arg_defn.name] = arg_defn
85
+ when Array
86
+ prev_defn << arg_defn
87
+ when GraphQL::Schema::Argument
88
+ own_arguments[arg_defn.name] = [prev_defn, arg_defn]
89
+ else
90
+ raise "Invariant: unexpected `@own_arguments[#{arg_defn.name.inspect}]`: #{prev_defn.inspect}"
91
+ end
47
92
  arg_defn
48
93
  end
49
94
 
50
95
  # @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
51
- def arguments
52
- inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments : nil)
96
+ def arguments(context = GraphQL::Query::NullContext)
97
+ inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments(context) : nil)
53
98
  # Local definitions override inherited ones
99
+ if own_arguments.any?
100
+ own_arguments_that_apply = {}
101
+ own_arguments.each do |name, args_entry|
102
+ if (visible_defn = Warden.visible_entry?(:visible_argument?, args_entry, context))
103
+ own_arguments_that_apply[visible_defn.graphql_name] = visible_defn
104
+ end
105
+ end
106
+ end
107
+
54
108
  if inherited_arguments
55
- inherited_arguments.merge(own_arguments)
109
+ if own_arguments_that_apply
110
+ inherited_arguments.merge(own_arguments_that_apply)
111
+ else
112
+ inherited_arguments
113
+ end
56
114
  else
57
- own_arguments
115
+ # might be nil if there are actually no arguments
116
+ own_arguments_that_apply || own_arguments
117
+ end
118
+ end
119
+
120
+ def all_argument_definitions
121
+ if self.is_a?(Class)
122
+ all_defns = {}
123
+ ancestors.reverse_each do |ancestor|
124
+ if ancestor.respond_to?(:own_arguments)
125
+ all_defns.merge!(ancestor.own_arguments)
126
+ end
127
+ end
128
+ else
129
+ all_defns = own_arguments
130
+ end
131
+ all_defns = all_defns.values
132
+ all_defns.flatten!
133
+ all_defns
134
+ end
135
+
136
+ # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
137
+ def get_argument(argument_name, context = GraphQL::Query::NullContext)
138
+ warden = Warden.from_context(context)
139
+ if !self.is_a?(Class)
140
+ a = own_arguments[argument_name]
141
+ a && Warden.visible_entry?(:visible_argument?, a, context, warden)
142
+ else
143
+ for ancestor in ancestors
144
+ if ancestor.respond_to?(:own_arguments) &&
145
+ (a = ancestor.own_arguments[argument_name]) &&
146
+ (a = Warden.visible_entry?(:visible_argument?, a, context, warden))
147
+ return a
148
+ end
149
+ end
150
+ nil
58
151
  end
59
152
  end
60
153
 
@@ -63,12 +156,94 @@ module GraphQL
63
156
  self.class.argument_class(new_arg_class)
64
157
  end
65
158
 
159
+ # @api private
160
+ # If given a block, it will eventually yield the loaded args to the block.
161
+ #
162
+ # If no block is given, it will immediately dataload (but might return a Lazy).
163
+ #
164
+ # @param values [Hash<String, Object>]
165
+ # @param context [GraphQL::Query::Context]
166
+ # @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
167
+ # @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
168
+ def coerce_arguments(parent_object, values, context, &block)
169
+ # Cache this hash to avoid re-merging it
170
+ arg_defns = context.warden.arguments(self)
171
+ total_args_count = arg_defns.size
172
+
173
+ finished_args = nil
174
+ prepare_finished_args = -> {
175
+ if total_args_count == 0
176
+ finished_args = GraphQL::Execution::Interpreter::Arguments::EMPTY
177
+ if block_given?
178
+ block.call(finished_args)
179
+ end
180
+ else
181
+ argument_values = {}
182
+ resolved_args_count = 0
183
+ raised_error = false
184
+ arg_defns.each do |arg_defn|
185
+ context.dataloader.append_job do
186
+ begin
187
+ arg_defn.coerce_into_values(parent_object, values, context, argument_values)
188
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
189
+ raised_error = true
190
+ finished_args = err
191
+ if block_given?
192
+ block.call(finished_args)
193
+ end
194
+ end
195
+
196
+ resolved_args_count += 1
197
+ if resolved_args_count == total_args_count && !raised_error
198
+ finished_args = context.schema.after_any_lazies(argument_values.values) {
199
+ GraphQL::Execution::Interpreter::Arguments.new(
200
+ argument_values: argument_values,
201
+ )
202
+ }
203
+ if block_given?
204
+ block.call(finished_args)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+ }
211
+
212
+ if block_given?
213
+ prepare_finished_args.call
214
+ nil
215
+ else
216
+ # This API returns eagerly, gotta run it now
217
+ context.dataloader.run_isolated(&prepare_finished_args)
218
+ finished_args
219
+ end
220
+ end
221
+
222
+ # Usually, this is validated statically by RequiredArgumentsArePresent,
223
+ # but not for directives.
224
+ # TODO apply static validations on schema definitions?
225
+ def validate_directive_argument(arg_defn, value)
226
+ if arg_defn.owner.is_a?(Class) && arg_defn.owner < GraphQL::Schema::Directive
227
+ if value.nil? && arg_defn.type.non_null?
228
+ raise ArgumentError, "#{arg_defn.path} is required, but no value was given"
229
+ end
230
+ end
231
+ end
232
+
233
+ def arguments_statically_coercible?
234
+ return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
235
+
236
+ @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
237
+ end
238
+
66
239
  module ArgumentClassAccessor
67
240
  def argument_class(new_arg_class = nil)
68
241
  if new_arg_class
69
242
  @argument_class = new_arg_class
243
+ elsif defined?(@argument_class) && @argument_class
244
+ @argument_class
70
245
  else
71
- @argument_class || (superclass.respond_to?(:argument_class) ? superclass.argument_class : GraphQL::Schema::Argument)
246
+ superclass.respond_to?(:argument_class) ? superclass.argument_class : GraphQL::Schema::Argument
72
247
  end
73
248
  end
74
249
  end
@@ -85,9 +260,20 @@ module GraphQL
85
260
  context.schema.object_from_id(id, context)
86
261
  end
87
262
 
88
- def load_application_object(argument, lookup_as_type, id)
263
+ def load_application_object(argument, id, context)
89
264
  # See if any object can be found for this ID
90
- loaded_application_object = object_from_id(lookup_as_type, id, context)
265
+ if id.nil?
266
+ return nil
267
+ end
268
+ object_from_id(argument.loads, id, context)
269
+ end
270
+
271
+ def load_and_authorize_application_object(argument, id, context)
272
+ loaded_application_object = load_application_object(argument, id, context)
273
+ authorize_application_object(argument, id, context, loaded_application_object)
274
+ end
275
+
276
+ def authorize_application_object(argument, id, context, loaded_application_object)
91
277
  context.schema.after_lazy(loaded_application_object) do |application_object|
92
278
  if application_object.nil?
93
279
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
@@ -95,9 +281,9 @@ module GraphQL
95
281
  end
96
282
  # Double-check that the located object is actually of this type
97
283
  # (Don't want to allow arbitrary access to objects this way)
98
- resolved_application_object_type = context.schema.resolve_type(lookup_as_type, application_object, context)
284
+ resolved_application_object_type = context.schema.resolve_type(argument.loads, application_object, context)
99
285
  context.schema.after_lazy(resolved_application_object_type) do |application_object_type|
100
- possible_object_types = context.schema.possible_types(lookup_as_type)
286
+ possible_object_types = context.warden.possible_types(argument.loads)
101
287
  if !possible_object_types.include?(application_object_type)
102
288
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
103
289
  load_application_object_failed(err)
@@ -105,16 +291,22 @@ module GraphQL
105
291
  # This object was loaded successfully
106
292
  # and resolved to the right type,
107
293
  # now apply the `.authorized?` class method if there is one
108
- if (class_based_type = application_object_type.metadata[:type_class])
294
+ if (class_based_type = application_object_type.type_class)
109
295
  context.schema.after_lazy(class_based_type.authorized?(application_object, context)) do |authed|
110
296
  if authed
111
297
  application_object
112
298
  else
113
- raise GraphQL::UnauthorizedError.new(
299
+ err = GraphQL::UnauthorizedError.new(
114
300
  object: application_object,
115
301
  type: class_based_type,
116
302
  context: context,
117
303
  )
304
+ if self.respond_to?(:unauthorized_object)
305
+ err.set_backtrace(caller)
306
+ unauthorized_object(err)
307
+ else
308
+ raise err
309
+ end
118
310
  end
119
311
  end
120
312
  else
@@ -130,8 +322,9 @@ module GraphQL
130
322
  end
131
323
  end
132
324
 
325
+ NO_ARGUMENTS = {}.freeze
133
326
  def own_arguments
134
- @own_arguments ||= {}
327
+ @own_arguments || NO_ARGUMENTS
135
328
  end
136
329
  end
137
330
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Member
5
+ module HasAstNode
6
+ # If this schema was parsed from a `.graphql` file (or other SDL),
7
+ # this is the AST node that defined this part of the schema.
8
+ def ast_node(new_ast_node = nil)
9
+ if new_ast_node
10
+ @ast_node = new_ast_node
11
+ elsif defined?(@ast_node)
12
+ @ast_node
13
+ else
14
+ nil
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDeprecationReason
7
+ # @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
8
+ def deprecation_reason
9
+ dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
10
+ dir && dir.arguments[:reason] # rubocop:disable Development/ContextIsPassedCop -- definition-related
11
+ end
12
+
13
+ # Set the deprecation reason for this member, or remove it by assigning `nil`
14
+ # @param text [String, nil]
15
+ def deprecation_reason=(text)
16
+ if text.nil?
17
+ remove_directive(GraphQL::Schema::Directive::Deprecated)
18
+ else
19
+ directive(GraphQL::Schema::Directive::Deprecated, reason: text)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDirectives
7
+ # Create an instance of `dir_class` for `self`, using `options`.
8
+ #
9
+ # It removes a previously-attached instance of `dir_class`, if there is one.
10
+ #
11
+ # @return [void]
12
+ def directive(dir_class, **options)
13
+ @own_directives ||= []
14
+ remove_directive(dir_class)
15
+ @own_directives << dir_class.new(self, **options)
16
+ nil
17
+ end
18
+
19
+ # Remove an attached instance of `dir_class`, if there is one
20
+ # @param dir_class [Class<GraphQL::Schema::Directive>]
21
+ # @return [viod]
22
+ def remove_directive(dir_class)
23
+ @own_directives && @own_directives.reject! { |d| d.is_a?(dir_class) }
24
+ nil
25
+ end
26
+
27
+ NO_DIRECTIVES = [].freeze
28
+
29
+ def directives
30
+ case self
31
+ when Class
32
+ inherited_directives = if superclass.respond_to?(:directives)
33
+ superclass.directives
34
+ else
35
+ NO_DIRECTIVES
36
+ end
37
+ if inherited_directives.any? && @own_directives
38
+ dirs = []
39
+ merge_directives(dirs, inherited_directives)
40
+ merge_directives(dirs, @own_directives)
41
+ dirs
42
+ elsif @own_directives
43
+ @own_directives
44
+ elsif inherited_directives.any?
45
+ inherited_directives
46
+ else
47
+ NO_DIRECTIVES
48
+ end
49
+ when Module
50
+ dirs = nil
51
+ self.ancestors.reverse_each do |ancestor|
52
+ if ancestor.respond_to?(:own_directives) &&
53
+ (anc_dirs = ancestor.own_directives).any?
54
+ dirs ||= []
55
+ merge_directives(dirs, anc_dirs)
56
+ end
57
+ end
58
+ if own_directives
59
+ dirs ||= []
60
+ merge_directives(dirs, own_directives)
61
+ end
62
+ dirs || NO_DIRECTIVES
63
+ when HasDirectives
64
+ @own_directives || NO_DIRECTIVES
65
+ else
66
+ raise "Invariant: how could #{self} not be a Class, Module, or instance of HasDirectives?"
67
+ end
68
+ end
69
+
70
+ protected
71
+
72
+ def own_directives
73
+ @own_directives
74
+ end
75
+
76
+ private
77
+
78
+ # Modify `target` by adding items from `dirs` such that:
79
+ # - Any name conflict is overriden by the incoming member of `dirs`
80
+ # - Any other member of `dirs` is appended
81
+ # @param target [Array<GraphQL::Schema::Directive>]
82
+ # @param dirs [Array<GraphQL::Schema::Directive>]
83
+ # @return [void]
84
+ def merge_directives(target, dirs)
85
+ dirs.each do |dir|
86
+ if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
87
+ target.slice!(idx)
88
+ target.insert(idx, dir)
89
+ else
90
+ target << dir
91
+ end
92
+ end
93
+ nil
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end