graphql 1.12.12 → 2.4.8

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

Potentially problematic release.


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

Files changed (428) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  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 +60 -4
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_generator.rb +5 -30
  14. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  15. data/lib/generators/graphql/object_generator.rb +10 -38
  16. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  17. data/lib/generators/graphql/relay.rb +23 -12
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  20. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  21. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  22. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  23. data/lib/generators/graphql/templates/base_field.erb +2 -0
  24. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  25. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  26. data/lib/generators/graphql/templates/base_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  28. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  29. data/lib/generators/graphql/templates/base_union.erb +2 -0
  30. data/lib/generators/graphql/templates/enum.erb +5 -1
  31. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  32. data/lib/generators/graphql/templates/input.erb +9 -0
  33. data/lib/generators/graphql/templates/interface.erb +4 -2
  34. data/lib/generators/graphql/templates/loader.erb +2 -0
  35. data/lib/generators/graphql/templates/mutation.erb +3 -1
  36. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  37. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  39. data/lib/generators/graphql/templates/node_type.erb +2 -0
  40. data/lib/generators/graphql/templates/object.erb +4 -2
  41. data/lib/generators/graphql/templates/query_type.erb +2 -0
  42. data/lib/generators/graphql/templates/scalar.erb +3 -1
  43. data/lib/generators/graphql/templates/schema.erb +22 -2
  44. data/lib/generators/graphql/templates/union.erb +4 -2
  45. data/lib/generators/graphql/type_generator.rb +46 -10
  46. data/lib/generators/graphql/union_generator.rb +5 -5
  47. data/lib/graphql/analysis/analyzer.rb +89 -0
  48. data/lib/graphql/analysis/field_usage.rb +65 -28
  49. data/lib/graphql/analysis/max_query_complexity.rb +11 -17
  50. data/lib/graphql/analysis/max_query_depth.rb +13 -19
  51. data/lib/graphql/analysis/query_complexity.rb +156 -61
  52. data/lib/graphql/analysis/query_depth.rb +38 -23
  53. data/lib/graphql/analysis/visitor.rb +283 -0
  54. data/lib/graphql/analysis.rb +90 -6
  55. data/lib/graphql/autoload.rb +38 -0
  56. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  57. data/lib/graphql/backtrace/table.rb +4 -22
  58. data/lib/graphql/backtrace/trace.rb +93 -0
  59. data/lib/graphql/backtrace/tracer.rb +8 -6
  60. data/lib/graphql/backtrace.rb +3 -8
  61. data/lib/graphql/coercion_error.rb +1 -9
  62. data/lib/graphql/current.rb +52 -0
  63. data/lib/graphql/dataloader/async_dataloader.rb +89 -0
  64. data/lib/graphql/dataloader/null_dataloader.rb +4 -2
  65. data/lib/graphql/dataloader/request.rb +5 -0
  66. data/lib/graphql/dataloader/source.rb +125 -33
  67. data/lib/graphql/dataloader.rb +193 -143
  68. data/lib/graphql/date_encoding_error.rb +16 -0
  69. data/lib/graphql/dig.rb +1 -1
  70. data/lib/graphql/duration_encoding_error.rb +16 -0
  71. data/lib/graphql/execution/errors.rb +12 -81
  72. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  73. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  74. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -36
  75. data/lib/graphql/execution/interpreter/resolve.rb +38 -4
  76. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  77. data/lib/graphql/execution/interpreter/runtime.rb +447 -403
  78. data/lib/graphql/execution/interpreter.rb +126 -80
  79. data/lib/graphql/execution/lazy.rb +11 -21
  80. data/lib/graphql/execution/lookahead.rb +133 -55
  81. data/lib/graphql/execution/multiplex.rb +4 -172
  82. data/lib/graphql/execution.rb +11 -4
  83. data/lib/graphql/integer_encoding_error.rb +18 -2
  84. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  85. data/lib/graphql/introspection/directive_type.rb +6 -4
  86. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  87. data/lib/graphql/introspection/entry_points.rb +11 -18
  88. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  89. data/lib/graphql/introspection/field_type.rb +4 -4
  90. data/lib/graphql/introspection/input_value_type.rb +10 -4
  91. data/lib/graphql/introspection/schema_type.rb +17 -15
  92. data/lib/graphql/introspection/type_type.rb +29 -16
  93. data/lib/graphql/introspection.rb +6 -2
  94. data/lib/graphql/invalid_null_error.rb +1 -1
  95. data/lib/graphql/language/block_string.rb +37 -25
  96. data/lib/graphql/language/cache.rb +13 -0
  97. data/lib/graphql/language/comment.rb +18 -0
  98. data/lib/graphql/language/definition_slice.rb +1 -1
  99. data/lib/graphql/language/document_from_schema_definition.rb +122 -81
  100. data/lib/graphql/language/lexer.rb +364 -1467
  101. data/lib/graphql/language/nodes.rb +197 -106
  102. data/lib/graphql/language/parser.rb +799 -1920
  103. data/lib/graphql/language/printer.rb +372 -160
  104. data/lib/graphql/language/sanitized_printer.rb +25 -27
  105. data/lib/graphql/language/static_visitor.rb +167 -0
  106. data/lib/graphql/language/visitor.rb +188 -141
  107. data/lib/graphql/language.rb +62 -1
  108. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  109. data/lib/graphql/name_validator.rb +0 -4
  110. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  111. data/lib/graphql/pagination/array_connection.rb +8 -6
  112. data/lib/graphql/pagination/connection.rb +61 -7
  113. data/lib/graphql/pagination/connections.rb +22 -23
  114. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  115. data/lib/graphql/pagination/relation_connection.rb +60 -28
  116. data/lib/graphql/query/context/scoped_context.rb +101 -0
  117. data/lib/graphql/query/context.rb +146 -222
  118. data/lib/graphql/query/input_validation_result.rb +10 -1
  119. data/lib/graphql/query/null_context.rb +15 -32
  120. data/lib/graphql/query/validation_pipeline.rb +15 -39
  121. data/lib/graphql/query/variable_validation_error.rb +3 -3
  122. data/lib/graphql/query/variables.rb +35 -17
  123. data/lib/graphql/query.rb +149 -82
  124. data/lib/graphql/railtie.rb +15 -109
  125. data/lib/graphql/rake_task/validate.rb +1 -1
  126. data/lib/graphql/rake_task.rb +30 -11
  127. data/lib/graphql/relay/range_add.rb +9 -16
  128. data/lib/graphql/relay.rb +0 -15
  129. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  130. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  131. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  132. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  133. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  134. data/lib/graphql/rubocop.rb +6 -0
  135. data/lib/graphql/schema/addition.rb +98 -54
  136. data/lib/graphql/schema/always_visible.rb +14 -0
  137. data/lib/graphql/schema/argument.rb +179 -82
  138. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  139. data/lib/graphql/schema/build_from_definition.rb +77 -39
  140. data/lib/graphql/schema/directive/feature.rb +1 -1
  141. data/lib/graphql/schema/directive/flagged.rb +4 -4
  142. data/lib/graphql/schema/directive/include.rb +1 -1
  143. data/lib/graphql/schema/directive/one_of.rb +24 -0
  144. data/lib/graphql/schema/directive/skip.rb +1 -1
  145. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  146. data/lib/graphql/schema/directive/transform.rb +2 -2
  147. data/lib/graphql/schema/directive.rb +36 -22
  148. data/lib/graphql/schema/enum.rb +158 -63
  149. data/lib/graphql/schema/enum_value.rb +12 -21
  150. data/lib/graphql/schema/field/connection_extension.rb +7 -17
  151. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  152. data/lib/graphql/schema/field.rb +521 -359
  153. data/lib/graphql/schema/field_extension.rb +86 -2
  154. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  155. data/lib/graphql/schema/finder.rb +5 -5
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +148 -99
  158. data/lib/graphql/schema/interface.rb +41 -64
  159. data/lib/graphql/schema/introspection_system.rb +12 -26
  160. data/lib/graphql/schema/late_bound_type.rb +12 -2
  161. data/lib/graphql/schema/list.rb +18 -7
  162. data/lib/graphql/schema/loader.rb +6 -5
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
  164. data/lib/graphql/schema/member/build_type.rb +16 -13
  165. data/lib/graphql/schema/member/has_arguments.rb +270 -86
  166. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  168. data/lib/graphql/schema/member/has_directives.rb +81 -61
  169. data/lib/graphql/schema/member/has_fields.rb +169 -31
  170. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +32 -6
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  176. data/lib/graphql/schema/member/validates_input.rb +6 -6
  177. data/lib/graphql/schema/member.rb +1 -6
  178. data/lib/graphql/schema/mutation.rb +7 -9
  179. data/lib/graphql/schema/non_null.rb +7 -7
  180. data/lib/graphql/schema/object.rb +38 -119
  181. data/lib/graphql/schema/printer.rb +24 -25
  182. data/lib/graphql/schema/relay_classic_mutation.rb +13 -91
  183. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  184. data/lib/graphql/schema/resolver.rb +118 -115
  185. data/lib/graphql/schema/scalar.rb +20 -21
  186. data/lib/graphql/schema/subscription.rb +95 -21
  187. data/lib/graphql/schema/timeout.rb +25 -29
  188. data/lib/graphql/schema/type_expression.rb +2 -2
  189. data/lib/graphql/schema/type_membership.rb +21 -4
  190. data/lib/graphql/schema/union.rb +16 -16
  191. data/lib/graphql/schema/unique_within_type.rb +1 -1
  192. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  193. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  194. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  195. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  196. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  197. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  198. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  199. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  200. data/lib/graphql/schema/validator/required_validator.rb +56 -18
  201. data/lib/graphql/schema/validator.rb +38 -28
  202. data/lib/graphql/schema/visibility/migration.rb +188 -0
  203. data/lib/graphql/schema/visibility/profile.rb +359 -0
  204. data/lib/graphql/schema/visibility/visit.rb +190 -0
  205. data/lib/graphql/schema/visibility.rb +294 -0
  206. data/lib/graphql/schema/warden.rb +423 -134
  207. data/lib/graphql/schema/wrapper.rb +0 -5
  208. data/lib/graphql/schema.rb +1015 -1057
  209. data/lib/graphql/static_validation/all_rules.rb +3 -1
  210. data/lib/graphql/static_validation/base_visitor.rb +15 -28
  211. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  212. data/lib/graphql/static_validation/error.rb +3 -1
  213. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  215. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  216. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +4 -3
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +15 -13
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +13 -5
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +62 -35
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  225. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  226. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  227. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  228. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  229. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  230. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  231. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  232. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  233. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -5
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  235. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  236. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +14 -8
  237. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  238. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  239. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  240. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  241. data/lib/graphql/static_validation/validation_context.rb +32 -6
  242. data/lib/graphql/static_validation/validator.rb +11 -27
  243. data/lib/graphql/static_validation.rb +0 -3
  244. data/lib/graphql/string_encoding_error.rb +13 -3
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -11
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  247. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
  248. data/lib/graphql/subscriptions/event.rb +87 -38
  249. data/lib/graphql/subscriptions/serialize.rb +27 -3
  250. data/lib/graphql/subscriptions.rb +63 -49
  251. data/lib/graphql/testing/helpers.rb +155 -0
  252. data/lib/graphql/testing.rb +2 -0
  253. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  254. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  255. data/lib/graphql/tracing/appoptics_trace.rb +253 -0
  256. data/lib/graphql/tracing/appoptics_tracing.rb +4 -2
  257. data/lib/graphql/tracing/appsignal_trace.rb +79 -0
  258. data/lib/graphql/tracing/appsignal_tracing.rb +17 -0
  259. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  260. data/lib/graphql/tracing/data_dog_trace.rb +185 -0
  261. data/lib/graphql/tracing/data_dog_tracing.rb +27 -15
  262. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
  263. data/lib/graphql/tracing/legacy_trace.rb +12 -0
  264. data/lib/graphql/tracing/new_relic_trace.rb +77 -0
  265. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  266. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  267. data/lib/graphql/tracing/notifications_tracing.rb +61 -0
  268. data/lib/graphql/tracing/null_trace.rb +9 -0
  269. data/lib/graphql/tracing/platform_trace.rb +118 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
  272. data/lib/graphql/tracing/prometheus_trace.rb +94 -0
  273. data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
  274. data/lib/graphql/tracing/scout_trace.rb +74 -0
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +114 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +58 -0
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +79 -0
  280. data/lib/graphql/tracing.rb +29 -52
  281. data/lib/graphql/type_kinds.rb +7 -4
  282. data/lib/graphql/types/big_int.rb +5 -1
  283. data/lib/graphql/types/int.rb +1 -1
  284. data/lib/graphql/types/iso_8601_date.rb +17 -6
  285. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  286. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  287. data/lib/graphql/types/relay/base_connection.rb +16 -6
  288. data/lib/graphql/types/relay/connection_behaviors.rb +92 -32
  289. data/lib/graphql/types/relay/edge_behaviors.rb +46 -7
  290. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  291. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  292. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  293. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  294. data/lib/graphql/types/relay.rb +0 -3
  295. data/lib/graphql/types/string.rb +2 -2
  296. data/lib/graphql/types.rb +18 -10
  297. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  298. data/lib/graphql/unauthorized_error.rb +1 -1
  299. data/lib/graphql/version.rb +1 -1
  300. data/lib/graphql.rb +82 -137
  301. data/readme.md +13 -6
  302. metadata +127 -186
  303. data/lib/graphql/analysis/analyze_query.rb +0 -98
  304. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  305. data/lib/graphql/analysis/ast/field_usage.rb +0 -28
  306. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
  307. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  308. data/lib/graphql/analysis/ast/query_complexity.rb +0 -234
  309. data/lib/graphql/analysis/ast/query_depth.rb +0 -56
  310. data/lib/graphql/analysis/ast/visitor.rb +0 -268
  311. data/lib/graphql/analysis/ast.rb +0 -91
  312. data/lib/graphql/analysis/reducer_state.rb +0 -48
  313. data/lib/graphql/argument.rb +0 -131
  314. data/lib/graphql/authorization.rb +0 -82
  315. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  316. data/lib/graphql/backwards_compatibility.rb +0 -61
  317. data/lib/graphql/base_type.rb +0 -230
  318. data/lib/graphql/boolean_type.rb +0 -2
  319. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  320. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  321. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  322. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  323. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  324. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  325. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  326. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  327. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  328. data/lib/graphql/compatibility.rb +0 -5
  329. data/lib/graphql/define/assign_argument.rb +0 -12
  330. data/lib/graphql/define/assign_connection.rb +0 -13
  331. data/lib/graphql/define/assign_enum_value.rb +0 -18
  332. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  333. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  334. data/lib/graphql/define/assign_object_field.rb +0 -42
  335. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  336. data/lib/graphql/define/instance_definable.rb +0 -240
  337. data/lib/graphql/define/no_definition_error.rb +0 -7
  338. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  339. data/lib/graphql/define/type_definer.rb +0 -31
  340. data/lib/graphql/define.rb +0 -31
  341. data/lib/graphql/deprecated_dsl.rb +0 -47
  342. data/lib/graphql/deprecation.rb +0 -13
  343. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  344. data/lib/graphql/directive/include_directive.rb +0 -2
  345. data/lib/graphql/directive/skip_directive.rb +0 -2
  346. data/lib/graphql/directive.rb +0 -111
  347. data/lib/graphql/enum_type.rb +0 -129
  348. data/lib/graphql/execution/execute.rb +0 -333
  349. data/lib/graphql/execution/flatten.rb +0 -40
  350. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  351. data/lib/graphql/execution/typecast.rb +0 -50
  352. data/lib/graphql/field/resolve.rb +0 -59
  353. data/lib/graphql/field.rb +0 -226
  354. data/lib/graphql/filter.rb +0 -53
  355. data/lib/graphql/float_type.rb +0 -2
  356. data/lib/graphql/function.rb +0 -128
  357. data/lib/graphql/id_type.rb +0 -2
  358. data/lib/graphql/input_object_type.rb +0 -138
  359. data/lib/graphql/int_type.rb +0 -2
  360. data/lib/graphql/interface_type.rb +0 -72
  361. data/lib/graphql/internal_representation/document.rb +0 -27
  362. data/lib/graphql/internal_representation/node.rb +0 -206
  363. data/lib/graphql/internal_representation/print.rb +0 -51
  364. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  365. data/lib/graphql/internal_representation/scope.rb +0 -88
  366. data/lib/graphql/internal_representation/visit.rb +0 -36
  367. data/lib/graphql/internal_representation.rb +0 -7
  368. data/lib/graphql/language/lexer.rl +0 -262
  369. data/lib/graphql/language/parser.y +0 -543
  370. data/lib/graphql/language/token.rb +0 -38
  371. data/lib/graphql/list_type.rb +0 -80
  372. data/lib/graphql/non_null_type.rb +0 -71
  373. data/lib/graphql/object_type.rb +0 -130
  374. data/lib/graphql/query/arguments.rb +0 -189
  375. data/lib/graphql/query/arguments_cache.rb +0 -24
  376. data/lib/graphql/query/executor.rb +0 -52
  377. data/lib/graphql/query/literal_input.rb +0 -136
  378. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  379. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  380. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  381. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  382. data/lib/graphql/query/serial_execution.rb +0 -40
  383. data/lib/graphql/relay/array_connection.rb +0 -83
  384. data/lib/graphql/relay/base_connection.rb +0 -189
  385. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  386. data/lib/graphql/relay/connection_resolve.rb +0 -43
  387. data/lib/graphql/relay/connection_type.rb +0 -41
  388. data/lib/graphql/relay/edge.rb +0 -27
  389. data/lib/graphql/relay/edge_type.rb +0 -19
  390. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  391. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  392. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  393. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  394. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  395. data/lib/graphql/relay/mutation/result.rb +0 -38
  396. data/lib/graphql/relay/mutation.rb +0 -106
  397. data/lib/graphql/relay/node.rb +0 -39
  398. data/lib/graphql/relay/page_info.rb +0 -7
  399. data/lib/graphql/relay/relation_connection.rb +0 -188
  400. data/lib/graphql/relay/type_extensions.rb +0 -32
  401. data/lib/graphql/scalar_type.rb +0 -91
  402. data/lib/graphql/schema/base_64_bp.rb +0 -26
  403. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  404. data/lib/graphql/schema/default_parse_error.rb +0 -10
  405. data/lib/graphql/schema/default_type_error.rb +0 -17
  406. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  407. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  408. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  409. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  410. data/lib/graphql/schema/middleware_chain.rb +0 -82
  411. data/lib/graphql/schema/possible_types.rb +0 -44
  412. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  413. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  414. data/lib/graphql/schema/traversal.rb +0 -228
  415. data/lib/graphql/schema/validation.rb +0 -313
  416. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  417. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  418. data/lib/graphql/static_validation/type_stack.rb +0 -216
  419. data/lib/graphql/string_type.rb +0 -2
  420. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  421. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  422. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  423. data/lib/graphql/types/relay/default_relay.rb +0 -27
  424. data/lib/graphql/types/relay/node_field.rb +0 -25
  425. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  426. data/lib/graphql/union_type.rb +0 -115
  427. data/lib/graphql/upgrader/member.rb +0 -937
  428. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -4,58 +4,225 @@ require 'set'
4
4
 
5
5
  module GraphQL
6
6
  class Schema
7
- # Restrict access to a {GraphQL::Schema} with a user-defined filter.
7
+ # Restrict access to a {GraphQL::Schema} with a user-defined `visible?` implementations.
8
8
  #
9
9
  # When validating and executing a query, all access to schema members
10
10
  # should go through a warden. If you access the schema directly,
11
11
  # you may show a client something that it shouldn't be allowed to see.
12
12
  #
13
- # @example Hidding private fields
14
- # private_members = -> (member, ctx) { member.metadata[:private] }
15
- # result = Schema.execute(query_string, except: private_members)
16
- #
17
- # @example Custom filter implementation
18
- # # It must respond to `#call(member)`.
19
- # class MissingRequiredFlags
20
- # def initialize(user)
21
- # @user = user
22
- # end
23
- #
24
- # # Return `false` if any required flags are missing
25
- # def call(member, ctx)
26
- # member.metadata[:required_flags].any? do |flag|
27
- # !@user.has_flag?(flag)
28
- # end
29
- # end
30
- # end
31
- #
32
- # # Then, use the custom filter in query:
33
- # missing_required_flags = MissingRequiredFlags.new(current_user)
34
- #
35
- # # This query can only access members which match the user's flags
36
- # result = Schema.execute(query_string, except: missing_required_flags)
37
- #
38
13
  # @api private
39
14
  class Warden
40
- # @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
15
+ def self.from_context(context)
16
+ context.warden || PassThruWarden
17
+ rescue NoMethodError
18
+ # this might be a hash which won't respond to #warden
19
+ PassThruWarden
20
+ end
21
+
22
+ def self.types_from_context(context)
23
+ context.types || PassThruWarden
24
+ rescue NoMethodError
25
+ # this might be a hash which won't respond to #warden
26
+ PassThruWarden
27
+ end
28
+
29
+ def self.use(schema)
30
+ # no-op
31
+ end
32
+
33
+ # @param visibility_method [Symbol] a Warden method to call for this entry
34
+ # @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
35
+ # @param context [GraphQL::Query::Context]
36
+ # @param warden [Warden]
37
+ # @return [Object] `entry` or one of `entry`'s items if exactly one of them is visible for this context
38
+ # @return [nil] If neither `entry` nor any of `entry`'s items are visible for this context
39
+ def self.visible_entry?(visibility_method, entry, context, warden = Warden.from_context(context))
40
+ if entry.is_a?(Array)
41
+ visible_item = nil
42
+ entry.each do |item|
43
+ if warden.public_send(visibility_method, item, context)
44
+ if visible_item.nil?
45
+ visible_item = item
46
+ else
47
+ raise DuplicateNamesError.new(
48
+ duplicated_name: item.path, duplicated_definition_1: visible_item.inspect, duplicated_definition_2: item.inspect
49
+ )
50
+ end
51
+ end
52
+ end
53
+ visible_item
54
+ elsif warden.public_send(visibility_method, entry, context)
55
+ entry
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ # This is used when a caller provides a Hash for context.
62
+ # We want to call the schema's hooks, but we don't have a full-blown warden.
63
+ # The `context` arguments to these methods exist purely to simplify the code that
64
+ # calls methods on this object, so it will have everything it needs.
65
+ class PassThruWarden
66
+ class << self
67
+ def visible_field?(field, ctx); field.visible?(ctx); end
68
+ def visible_argument?(arg, ctx); arg.visible?(ctx); end
69
+ def visible_type?(type, ctx); type.visible?(ctx); end
70
+ def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
71
+ def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
72
+ def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
73
+ def arguments(owner, ctx); owner.arguments(ctx); end
74
+ def loadable?(type, ctx); type.visible?(ctx); end
75
+ def loadable_possible_types(type, ctx); type.possible_types(ctx); end
76
+ def visibility_profile
77
+ @visibility_profile ||= Warden::VisibilityProfile.new(self)
78
+ end
79
+ end
80
+ end
81
+
82
+ class NullWarden
83
+ def initialize(_filter = nil, context:, schema:)
84
+ @schema = schema
85
+ @visibility_profile = Warden::VisibilityProfile.new(self)
86
+ end
87
+
88
+ # No-op, but for compatibility:
89
+ attr_writer :skip_warning
90
+
91
+ attr_reader :visibility_profile
92
+
93
+ def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
94
+ def visible_argument?(arg_defn, _ctx = nil); true; end
95
+ def visible_type?(type_defn, _ctx = nil); true; end
96
+ def visible_enum_value?(enum_value, _ctx = nil); enum_value.visible?(Query::NullContext.instance); end
97
+ def visible_type_membership?(type_membership, _ctx = nil); true; end
98
+ def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
99
+ def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
100
+ def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
101
+ def enum_values(enum_defn); enum_defn.enum_values(Query::NullContext.instance); end # rubocop:disable Development/ContextIsPassedCop
102
+ def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
103
+ def types; @schema.types; end # rubocop:disable Development/ContextIsPassedCop
104
+ def root_type_for_operation(op_name); @schema.root_type_for_operation(op_name); end
105
+ def directives; @schema.directives.values; end
106
+ def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
107
+ def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
108
+ def reachable_type?(type_name); true; end
109
+ def loadable?(type, _ctx); true; end
110
+ def loadable_possible_types(union_type, _ctx); union_type.possible_types; end
111
+ def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
112
+ def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
113
+ def interfaces(obj_type); obj_type.interfaces; end
114
+ end
115
+
116
+ def visibility_profile
117
+ @visibility_profile ||= VisibilityProfile.new(self)
118
+ end
119
+
120
+ class VisibilityProfile
121
+ def initialize(warden)
122
+ @warden = warden
123
+ end
124
+
125
+ def directives
126
+ @warden.directives
127
+ end
128
+
129
+ def directive_exists?(dir_name)
130
+ @warden.directives.any? { |d| d.graphql_name == dir_name }
131
+ end
132
+
133
+ def type(name)
134
+ @warden.get_type(name)
135
+ end
136
+
137
+ def field(owner, field_name)
138
+ @warden.get_field(owner, field_name)
139
+ end
140
+
141
+ def argument(owner, arg_name)
142
+ @warden.get_argument(owner, arg_name)
143
+ end
144
+
145
+ def query_root
146
+ @warden.root_type_for_operation("query")
147
+ end
148
+
149
+ def mutation_root
150
+ @warden.root_type_for_operation("mutation")
151
+ end
152
+
153
+ def subscription_root
154
+ @warden.root_type_for_operation("subscription")
155
+ end
156
+
157
+ def arguments(owner)
158
+ @warden.arguments(owner)
159
+ end
160
+
161
+ def fields(owner)
162
+ @warden.fields(owner)
163
+ end
164
+
165
+ def possible_types(type)
166
+ @warden.possible_types(type)
167
+ end
168
+
169
+ def enum_values(enum_type)
170
+ @warden.enum_values(enum_type)
171
+ end
172
+
173
+ def all_types
174
+ @warden.reachable_types
175
+ end
176
+
177
+ def interfaces(obj_type)
178
+ @warden.interfaces(obj_type)
179
+ end
180
+
181
+ def loadable?(t, ctx) # TODO remove ctx here?
182
+ @warden.loadable?(t, ctx)
183
+ end
184
+
185
+ def loadable_possible_types(t, ctx)
186
+ @warden.loadable_possible_types(t, ctx)
187
+ end
188
+
189
+ def reachable_type?(type_name)
190
+ !!@warden.reachable_type?(type_name)
191
+ end
192
+
193
+ def visible_enum_value?(enum_value, ctx = nil)
194
+ @warden.visible_enum_value?(enum_value, ctx)
195
+ end
196
+ end
197
+
41
198
  # @param context [GraphQL::Query::Context]
42
199
  # @param schema [GraphQL::Schema]
43
- def initialize(filter, context:, schema:)
44
- @schema = schema.interpreter? ? schema : schema.graphql_definition
200
+ def initialize(context:, schema:)
201
+ @schema = schema
45
202
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
46
203
  @query = @schema.query
47
204
  @mutation = @schema.mutation
48
205
  @subscription = @schema.subscription
49
206
  @context = context
50
- @visibility_cache = read_through { |m| filter.call(m, context) }
207
+ @visibility_cache = read_through { |m| check_visible(schema, m) }
208
+ # Initialize all ivars to improve object shape consistency:
209
+ @types = @visible_types = @reachable_types = @visible_parent_fields =
210
+ @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
211
+ @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
212
+ @visible_and_reachable_type = @unions = @unfiltered_interfaces =
213
+ @reachable_type_set = @visibility_profile = @loadable_possible_types =
214
+ nil
215
+ @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
51
216
  end
52
217
 
218
+ attr_writer :skip_warning
219
+
53
220
  # @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
54
221
  def types
55
222
  @types ||= begin
56
223
  vis_types = {}
57
- @schema.types.each do |n, t|
58
- if visible_type?(t)
224
+ @schema.types(@context).each do |n, t|
225
+ if visible_and_reachable_type?(t)
59
226
  vis_types[n] = t
60
227
  end
61
228
  end
@@ -63,11 +230,23 @@ module GraphQL
63
230
  end
64
231
  end
65
232
 
233
+ # @return [Boolean] True if this type is used for `loads:` but not in the schema otherwise and not _explicitly_ hidden.
234
+ def loadable?(type, _ctx)
235
+ !reachable_type_set.include?(type) && visible_type?(type)
236
+ end
237
+
238
+ def loadable_possible_types(union_type, _ctx)
239
+ @loadable_possible_types ||= read_through do |t|
240
+ t.possible_types # unfiltered
241
+ end
242
+ @loadable_possible_types[union_type]
243
+ end
244
+
66
245
  # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
67
246
  def get_type(type_name)
68
247
  @visible_types ||= read_through do |name|
69
- type_defn = @schema.get_type(name)
70
- if type_defn && visible_type?(type_defn)
248
+ type_defn = @schema.get_type(name, @context, false)
249
+ if type_defn && visible_and_reachable_type?(type_defn)
71
250
  type_defn
72
251
  else
73
252
  nil
@@ -84,7 +263,7 @@ module GraphQL
84
263
 
85
264
  # @return Boolean True if the type is visible and reachable in the schema
86
265
  def reachable_type?(type_name)
87
- type = get_type(type_name)
266
+ type = get_type(type_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
88
267
  type && reachable_type_set.include?(type)
89
268
  end
90
269
 
@@ -92,8 +271,8 @@ module GraphQL
92
271
  def get_field(parent_type, field_name)
93
272
  @visible_parent_fields ||= read_through do |type|
94
273
  read_through do |f_name|
95
- field_defn = @schema.get_field(type, f_name)
96
- if field_defn && visible_field?(type, field_defn)
274
+ field_defn = @schema.get_field(type, f_name, @context)
275
+ if field_defn && visible_field?(field_defn, nil, type)
97
276
  field_defn
98
277
  else
99
278
  nil
@@ -106,15 +285,15 @@ module GraphQL
106
285
 
107
286
  # @return [GraphQL::Argument, nil] The argument named `argument_name` on `parent_type`, if it exists and is visible
108
287
  def get_argument(parent_type, argument_name)
109
- argument = parent_type.get_argument(argument_name)
110
- return argument if argument && visible_argument?(argument)
288
+ argument = parent_type.get_argument(argument_name, @context)
289
+ return argument if argument && visible_argument?(argument, @context)
111
290
  end
112
291
 
113
292
  # @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
114
293
  def possible_types(type_defn)
115
294
  @visible_possible_types ||= read_through { |type_defn|
116
- pt = @schema.possible_types(type_defn, @context)
117
- pt.select { |t| visible_type?(t) }
295
+ pt = @schema.possible_types(type_defn, @context, false)
296
+ pt.select { |t| visible_and_reachable_type?(t) }
118
297
  }
119
298
  @visible_possible_types[type_defn]
120
299
  end
@@ -122,26 +301,52 @@ module GraphQL
122
301
  # @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
123
302
  # @return [Array<GraphQL::Field>] Fields on `type_defn`
124
303
  def fields(type_defn)
125
- @visible_fields ||= read_through { |t| @schema.get_fields(t).each_value.select { |f| visible_field?(t, f) } }
304
+ @visible_fields ||= read_through { |t| @schema.get_fields(t, @context).values }
126
305
  @visible_fields[type_defn]
127
306
  end
128
307
 
129
308
  # @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
130
309
  # @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
131
- def arguments(argument_owner)
132
- @visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
310
+ def arguments(argument_owner, ctx = nil)
311
+ @visible_arguments ||= read_through { |o|
312
+ args = o.arguments(@context)
313
+ if !args.empty?
314
+ args = args.values
315
+ args.select! { |a| visible_argument?(a, @context) }
316
+ args
317
+ else
318
+ EmptyObjects::EMPTY_ARRAY
319
+ end
320
+ }
133
321
  @visible_arguments[argument_owner]
134
322
  end
135
323
 
136
324
  # @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
137
325
  def enum_values(enum_defn)
138
- @visible_enum_values ||= read_through { |e| e.values.each_value.select { |enum_value_defn| visible?(enum_value_defn) } }
139
- @visible_enum_values[enum_defn]
326
+ @visible_enum_arrays ||= read_through { |e|
327
+ values = e.enum_values(@context)
328
+ if values.size == 0
329
+ raise GraphQL::Schema::Enum::MissingValuesError.new(e)
330
+ end
331
+ values
332
+ }
333
+ @visible_enum_arrays[enum_defn]
334
+ end
335
+
336
+ def visible_enum_value?(enum_value, _ctx = nil)
337
+ @visible_enum_values ||= read_through { |ev| visible?(ev) }
338
+ @visible_enum_values[enum_value]
140
339
  end
141
340
 
142
341
  # @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
143
342
  def interfaces(obj_type)
144
- @visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible?(i) } }
343
+ @visible_interfaces ||= read_through { |t|
344
+ ints = t.interfaces(@context)
345
+ if !ints.empty?
346
+ ints.select! { |i| visible_type?(i) }
347
+ end
348
+ ints
349
+ }
145
350
  @visible_interfaces[obj_type]
146
351
  end
147
352
 
@@ -158,25 +363,74 @@ module GraphQL
158
363
  end
159
364
  end
160
365
 
161
- private
162
-
163
- def union_memberships(obj_type)
164
- @unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
165
- @unions[obj_type]
166
- end
167
-
168
- def visible_argument?(arg_defn)
169
- visible?(arg_defn) && visible_type?(arg_defn.type.unwrap)
170
- end
171
-
172
- def visible_field?(owner_type, field_defn)
366
+ # @param owner [Class, Module] If provided, confirm that field has the given owner.
367
+ def visible_field?(field_defn, _ctx = nil, owner = field_defn.owner)
173
368
  # This field is visible in its own right
174
369
  visible?(field_defn) &&
175
370
  # This field's return type is visible
176
- visible_type?(field_defn.type.unwrap) &&
371
+ visible_and_reachable_type?(field_defn.type.unwrap) &&
177
372
  # This field is either defined on this object type,
178
373
  # or the interface it's inherited from is also visible
179
- ((field_defn.respond_to?(:owner) && field_defn.owner == owner_type) || field_on_visible_interface?(field_defn, owner_type))
374
+ ((field_defn.respond_to?(:owner) && field_defn.owner == owner) || field_on_visible_interface?(field_defn, owner))
375
+ end
376
+
377
+ def visible_argument?(arg_defn, _ctx = nil)
378
+ visible?(arg_defn) && visible_and_reachable_type?(arg_defn.type.unwrap)
379
+ end
380
+
381
+ def visible_type?(type_defn, _ctx = nil)
382
+ @type_visibility ||= read_through { |type_defn| visible?(type_defn) }
383
+ @type_visibility[type_defn]
384
+ end
385
+
386
+ def visible_type_membership?(type_membership, _ctx = nil)
387
+ visible?(type_membership)
388
+ end
389
+
390
+ def interface_type_memberships(obj_type, _ctx = nil)
391
+ @type_memberships ||= read_through do |obj_t|
392
+ obj_t.interface_type_memberships
393
+ end
394
+ @type_memberships[obj_type]
395
+ end
396
+
397
+ private
398
+
399
+ def visible_and_reachable_type?(type_defn)
400
+ @visible_and_reachable_type ||= read_through do |type_defn|
401
+ next false unless visible_type?(type_defn)
402
+ next true if root_type?(type_defn) || type_defn.introspection?
403
+
404
+ if type_defn.kind.union?
405
+ !possible_types(type_defn).empty? && (referenced?(type_defn) || orphan_type?(type_defn))
406
+ elsif type_defn.kind.interface?
407
+ if !possible_types(type_defn).empty?
408
+ true
409
+ else
410
+ if @context.respond_to?(:logger) && (logger = @context.logger)
411
+ logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementers" }
412
+ end
413
+ false
414
+ end
415
+ else
416
+ if referenced?(type_defn)
417
+ true
418
+ elsif type_defn.kind.object?
419
+ # Show this object if it belongs to ...
420
+ interfaces(type_defn).any? { |t| referenced?(t) } || # an interface which is referenced in the schema
421
+ union_memberships(type_defn).any? { |t| referenced?(t) || orphan_type?(t) } # or a union which is referenced or added via orphan_types
422
+ else
423
+ false
424
+ end
425
+ end
426
+ end
427
+
428
+ @visible_and_reachable_type[type_defn]
429
+ end
430
+
431
+ def union_memberships(obj_type)
432
+ @unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
433
+ @unions[obj_type]
180
434
  end
181
435
 
182
436
  # We need this to tell whether a field was inherited by an interface
@@ -195,10 +449,10 @@ module GraphQL
195
449
  any_interface_has_visible_field = false
196
450
  ints = unfiltered_interfaces(type_defn)
197
451
  ints.each do |interface_type|
198
- if (iface_field_defn = interface_type.get_field(field_defn.graphql_name))
452
+ if (iface_field_defn = interface_type.get_field(field_defn.graphql_name, @context))
199
453
  any_interface_has_field = true
200
454
 
201
- if interfaces(type_defn).include?(interface_type) && visible_field?(interface_type, iface_field_defn)
455
+ if interfaces(type_defn).include?(interface_type) && visible_field?(iface_field_defn, nil, interface_type)
202
456
  any_interface_has_visible_field = true
203
457
  end
204
458
  end
@@ -215,23 +469,6 @@ module GraphQL
215
469
  end
216
470
  end
217
471
 
218
- def visible_type?(type_defn)
219
- @type_visibility ||= read_through do |type_defn|
220
- next false unless visible?(type_defn)
221
- next true if root_type?(type_defn) || type_defn.introspection?
222
-
223
- if type_defn.kind.union?
224
- visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
225
- elsif type_defn.kind.interface?
226
- visible_possible_types?(type_defn)
227
- else
228
- referenced?(type_defn) || visible_abstract_type?(type_defn)
229
- end
230
- end
231
-
232
- @type_visibility[type_defn]
233
- end
234
-
235
472
  def root_type?(type_defn)
236
473
  @query == type_defn ||
237
474
  @mutation == type_defn ||
@@ -239,41 +476,79 @@ module GraphQL
239
476
  end
240
477
 
241
478
  def referenced?(type_defn)
242
- @references_to ||= @schema.references_to
243
- graphql_name = type_defn.unwrap.graphql_name
244
- members = @references_to[graphql_name] || NO_REFERENCES
479
+ members = @schema.references_to(type_defn)
245
480
  members.any? { |m| visible?(m) }
246
481
  end
247
482
 
248
- NO_REFERENCES = [].freeze
249
-
250
483
  def orphan_type?(type_defn)
251
484
  @schema.orphan_types.include?(type_defn)
252
485
  end
253
486
 
254
- def visible_abstract_type?(type_defn)
255
- type_defn.kind.object? && (
256
- interfaces(type_defn).any? ||
257
- union_memberships(type_defn).any?
258
- )
259
- end
260
-
261
- def visible_possible_types?(type_defn)
262
- possible_types(type_defn).any? { |t| visible_type?(t) }
263
- end
264
-
265
487
  def visible?(member)
266
488
  @visibility_cache[member]
267
489
  end
268
490
 
269
491
  def read_through
270
- Hash.new { |h, k| h[k] = yield(k) }
492
+ Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
493
+ end
494
+
495
+ def check_visible(schema, member)
496
+ if schema.visible?(member, @context)
497
+ true
498
+ elsif @skip_warning
499
+ false
500
+ else
501
+ member_s = member.respond_to?(:path) ? member.path : member.inspect
502
+ member_type = case member
503
+ when Module
504
+ if member.respond_to?(:kind)
505
+ member.kind.name.downcase
506
+ else
507
+ ""
508
+ end
509
+ when GraphQL::Schema::Field
510
+ "field"
511
+ when GraphQL::Schema::EnumValue
512
+ "enum value"
513
+ when GraphQL::Schema::Argument
514
+ "argument"
515
+ else
516
+ ""
517
+ end
518
+
519
+ schema_s = schema.name ? "#{schema.name}'s" : ""
520
+ schema_name = schema.name ? "#{schema.name}" : "your schema"
521
+ warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
522
+ @skip_warning = true # only warn once per query
523
+ # If there's no schema name, add the backtrace for additional context:
524
+ if schema_s == ""
525
+ puts caller.map { |l| " #{l}"}
526
+ end
527
+ false
528
+ end
271
529
  end
272
530
 
531
+ ADD_WARDEN_WARNING = <<~WARNING
532
+ DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
533
+
534
+ Address this warning by adding:
535
+
536
+ use GraphQL::Schema::Visibility
537
+
538
+ to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
539
+
540
+ Alternatively, for legacy behavior, add:
541
+
542
+ use GraphQL::Schema::Warden # legacy visibility behavior
543
+
544
+ For more information see: https://graphql-ruby.org/authorization/visibility.html
545
+ WARNING
546
+
273
547
  def reachable_type_set
274
- return @reachable_type_set if defined?(@reachable_type_set)
548
+ return @reachable_type_set if @reachable_type_set
275
549
 
276
550
  @reachable_type_set = Set.new
551
+ rt_hash = {}
277
552
 
278
553
  unvisited_types = []
279
554
  ['query', 'mutation', 'subscription'].each do |op_name|
@@ -283,62 +558,76 @@ module GraphQL
283
558
  unvisited_types.concat(@schema.introspection_system.types.values)
284
559
 
285
560
  directives.each do |dir_class|
286
- dir_class.arguments.values.each do |arg_defn|
561
+ arguments(dir_class).each do |arg_defn|
287
562
  arg_t = arg_defn.type.unwrap
288
- if get_type(arg_t.graphql_name)
563
+ if get_type(arg_t.graphql_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
289
564
  unvisited_types << arg_t
290
565
  end
291
566
  end
292
567
  end
293
568
 
294
569
  @schema.orphan_types.each do |orphan_type|
295
- if get_type(orphan_type.graphql_name)
570
+ if get_type(orphan_type.graphql_name) == orphan_type # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
296
571
  unvisited_types << orphan_type
297
572
  end
298
573
  end
299
574
 
575
+ included_interface_possible_types_set = Set.new
576
+
300
577
  until unvisited_types.empty?
301
578
  type = unvisited_types.pop
302
- if @reachable_type_set.add?(type)
303
- if type.kind.input_object?
304
- # recurse into visible arguments
305
- arguments(type).each do |argument|
306
- argument_type = argument.type.unwrap
307
- unvisited_types << argument_type
308
- end
309
- elsif type.kind.union?
310
- # recurse into visible possible types
311
- possible_types(type).each do |possible_type|
312
- unvisited_types << possible_type
579
+ visit_type(type, unvisited_types, @reachable_type_set, rt_hash, included_interface_possible_types_set, include_interface_possible_types: false)
580
+ end
581
+
582
+ @reachable_type_set
583
+ end
584
+
585
+ def visit_type(type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types:)
586
+ if visited_type_set.add?(type) || (include_interface_possible_types && type.kind.interface? && included_interface_possible_types_set.add?(type))
587
+ type_by_name = type_by_name_hash[type.graphql_name] ||= type
588
+ if type_by_name != type
589
+ name_1, name_2 = [type.inspect, type_by_name.inspect].sort
590
+ raise DuplicateNamesError.new(
591
+ duplicated_name: type.graphql_name, duplicated_definition_1: name_1, duplicated_definition_2: name_2
592
+ )
593
+ end
594
+ if type.kind.input_object?
595
+ # recurse into visible arguments
596
+ arguments(type).each do |argument|
597
+ argument_type = argument.type.unwrap
598
+ unvisited_types << argument_type
599
+ end
600
+ elsif type.kind.union?
601
+ # recurse into visible possible types
602
+ possible_types(type).each do |possible_type|
603
+ unvisited_types << possible_type
604
+ end
605
+ elsif type.kind.fields?
606
+ if type.kind.object?
607
+ # recurse into visible implemented interfaces
608
+ interfaces(type).each do |interface|
609
+ unvisited_types << interface
313
610
  end
314
- elsif type.kind.fields?
315
- if type.kind.interface?
316
- # recurse into visible possible types
317
- possible_types(type).each do |possible_type|
318
- unvisited_types << possible_type
319
- end
320
- elsif type.kind.object?
321
- # recurse into visible implemented interfaces
322
- interfaces(type).each do |interface|
323
- unvisited_types << interface
324
- end
611
+ elsif include_interface_possible_types
612
+ possible_types(type).each do |pt|
613
+ unvisited_types << pt
325
614
  end
615
+ end
616
+ # Don't visit interface possible types -- it's not enough to justify visibility
326
617
 
327
- # recurse into visible fields
328
- fields(type).each do |field|
329
- field_type = field.type.unwrap
330
- unvisited_types << field_type
331
- # recurse into visible arguments
332
- arguments(field).each do |argument|
333
- argument_type = argument.type.unwrap
334
- unvisited_types << argument_type
335
- end
618
+ # recurse into visible fields
619
+ fields(type).each do |field|
620
+ field_type = field.type.unwrap
621
+ # In this case, if it's an interface, we want to include
622
+ visit_type(field_type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types: true)
623
+ # recurse into visible arguments
624
+ arguments(field).each do |argument|
625
+ argument_type = argument.type.unwrap
626
+ unvisited_types << argument_type
336
627
  end
337
628
  end
338
629
  end
339
630
  end
340
-
341
- @reachable_type_set
342
631
  end
343
632
  end
344
633
  end