graphql 2.0.32 → 2.5.22

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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  4. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  5. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  6. data/lib/generators/graphql/install_generator.rb +49 -0
  7. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  8. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  9. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  10. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  11. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  12. data/lib/generators/graphql/templates/base_field.erb +2 -0
  13. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  14. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  15. data/lib/generators/graphql/templates/base_object.erb +2 -0
  16. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  17. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  18. data/lib/generators/graphql/templates/base_union.erb +2 -0
  19. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +5 -0
  26. data/lib/generators/graphql/type_generator.rb +1 -1
  27. data/lib/graphql/analysis/analyzer.rb +90 -0
  28. data/lib/graphql/analysis/field_usage.rb +82 -0
  29. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  30. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  31. data/lib/graphql/analysis/query_complexity.rb +263 -0
  32. data/lib/graphql/analysis/query_depth.rb +58 -0
  33. data/lib/graphql/analysis/visitor.rb +280 -0
  34. data/lib/graphql/analysis.rb +95 -1
  35. data/lib/graphql/autoload.rb +38 -0
  36. data/lib/graphql/backtrace/table.rb +118 -55
  37. data/lib/graphql/backtrace.rb +1 -19
  38. data/lib/graphql/coercion_error.rb +1 -9
  39. data/lib/graphql/current.rb +57 -0
  40. data/lib/graphql/dashboard/application_controller.rb +41 -0
  41. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  42. data/lib/graphql/dashboard/installable.rb +22 -0
  43. data/lib/graphql/dashboard/landings_controller.rb +9 -0
  44. data/lib/graphql/dashboard/limiters.rb +93 -0
  45. data/lib/graphql/dashboard/operation_store.rb +199 -0
  46. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  47. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  48. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  49. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  50. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  51. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  52. data/lib/graphql/dashboard/statics/icon.png +0 -0
  53. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  54. data/lib/graphql/dashboard/subscriptions.rb +97 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  65. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  66. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  67. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  68. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  69. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  70. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  71. data/lib/graphql/dashboard.rb +96 -0
  72. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  73. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  74. data/lib/graphql/dataloader/async_dataloader.rb +112 -0
  75. data/lib/graphql/dataloader/null_dataloader.rb +55 -10
  76. data/lib/graphql/dataloader/request.rb +5 -0
  77. data/lib/graphql/dataloader/source.rb +35 -12
  78. data/lib/graphql/dataloader.rb +224 -149
  79. data/lib/graphql/date_encoding_error.rb +1 -1
  80. data/lib/graphql/dig.rb +2 -1
  81. data/lib/graphql/duration_encoding_error.rb +16 -0
  82. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  83. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  84. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  85. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
  86. data/lib/graphql/execution/interpreter/runtime.rb +363 -434
  87. data/lib/graphql/execution/interpreter.rb +91 -164
  88. data/lib/graphql/execution/lookahead.rb +105 -31
  89. data/lib/graphql/execution/multiplex.rb +7 -6
  90. data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
  91. data/lib/graphql/execution/next/load_argument_step.rb +60 -0
  92. data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
  93. data/lib/graphql/execution/next/runner.rb +389 -0
  94. data/lib/graphql/execution/next/selections_step.rb +37 -0
  95. data/lib/graphql/execution/next.rb +70 -0
  96. data/lib/graphql/execution.rb +1 -0
  97. data/lib/graphql/execution_error.rb +13 -10
  98. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  99. data/lib/graphql/introspection/directive_type.rb +7 -3
  100. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  101. data/lib/graphql/introspection/entry_points.rb +20 -6
  102. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  103. data/lib/graphql/introspection/field_type.rb +13 -5
  104. data/lib/graphql/introspection/input_value_type.rb +21 -13
  105. data/lib/graphql/introspection/schema_type.rb +8 -11
  106. data/lib/graphql/introspection/type_type.rb +64 -28
  107. data/lib/graphql/invalid_name_error.rb +1 -1
  108. data/lib/graphql/invalid_null_error.rb +26 -17
  109. data/lib/graphql/language/block_string.rb +34 -18
  110. data/lib/graphql/language/cache.rb +13 -0
  111. data/lib/graphql/language/comment.rb +18 -0
  112. data/lib/graphql/language/definition_slice.rb +1 -1
  113. data/lib/graphql/language/document_from_schema_definition.rb +90 -61
  114. data/lib/graphql/language/lexer.rb +319 -193
  115. data/lib/graphql/language/nodes.rb +136 -77
  116. data/lib/graphql/language/parser.rb +807 -1985
  117. data/lib/graphql/language/printer.rb +324 -151
  118. data/lib/graphql/language/sanitized_printer.rb +21 -23
  119. data/lib/graphql/language/static_visitor.rb +171 -0
  120. data/lib/graphql/language/visitor.rb +23 -83
  121. data/lib/graphql/language.rb +71 -1
  122. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  123. data/lib/graphql/pagination/array_connection.rb +6 -6
  124. data/lib/graphql/pagination/connection.rb +30 -1
  125. data/lib/graphql/pagination/connections.rb +32 -0
  126. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  127. data/lib/graphql/query/context/scoped_context.rb +101 -0
  128. data/lib/graphql/query/context.rb +82 -144
  129. data/lib/graphql/query/null_context.rb +15 -18
  130. data/lib/graphql/query/partial.rb +179 -0
  131. data/lib/graphql/query/validation_pipeline.rb +4 -4
  132. data/lib/graphql/query/variable_validation_error.rb +1 -1
  133. data/lib/graphql/query/variables.rb +3 -3
  134. data/lib/graphql/query.rb +126 -81
  135. data/lib/graphql/railtie.rb +16 -6
  136. data/lib/graphql/rake_task.rb +3 -12
  137. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  138. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  139. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  140. data/lib/graphql/rubocop.rb +2 -0
  141. data/lib/graphql/schema/addition.rb +26 -13
  142. data/lib/graphql/schema/always_visible.rb +7 -2
  143. data/lib/graphql/schema/argument.rb +75 -9
  144. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  145. data/lib/graphql/schema/build_from_definition.rb +123 -60
  146. data/lib/graphql/schema/directive/flagged.rb +4 -2
  147. data/lib/graphql/schema/directive/one_of.rb +12 -0
  148. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  149. data/lib/graphql/schema/directive.rb +54 -2
  150. data/lib/graphql/schema/enum.rb +110 -27
  151. data/lib/graphql/schema/enum_value.rb +10 -2
  152. data/lib/graphql/schema/field/connection_extension.rb +15 -49
  153. data/lib/graphql/schema/field/scope_extension.rb +23 -7
  154. data/lib/graphql/schema/field.rb +245 -118
  155. data/lib/graphql/schema/field_extension.rb +34 -1
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +116 -60
  158. data/lib/graphql/schema/interface.rb +34 -16
  159. data/lib/graphql/schema/introspection_system.rb +8 -17
  160. data/lib/graphql/schema/late_bound_type.rb +4 -0
  161. data/lib/graphql/schema/list.rb +3 -3
  162. data/lib/graphql/schema/loader.rb +3 -4
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
  164. data/lib/graphql/schema/member/has_arguments.rb +132 -100
  165. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  166. data/lib/graphql/schema/member/has_dataloader.rb +99 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  168. data/lib/graphql/schema/member/has_directives.rb +4 -4
  169. data/lib/graphql/schema/member/has_fields.rb +115 -15
  170. data/lib/graphql/schema/member/has_interfaces.rb +26 -12
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +1 -1
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  176. data/lib/graphql/schema/member/validates_input.rb +3 -3
  177. data/lib/graphql/schema/member.rb +6 -0
  178. data/lib/graphql/schema/mutation.rb +7 -0
  179. data/lib/graphql/schema/object.rb +34 -8
  180. data/lib/graphql/schema/printer.rb +9 -7
  181. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  182. data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
  183. data/lib/graphql/schema/resolver.rb +90 -32
  184. data/lib/graphql/schema/scalar.rb +4 -9
  185. data/lib/graphql/schema/subscription.rb +63 -10
  186. data/lib/graphql/schema/timeout.rb +19 -2
  187. data/lib/graphql/schema/type_expression.rb +2 -2
  188. data/lib/graphql/schema/union.rb +2 -2
  189. data/lib/graphql/schema/unique_within_type.rb +1 -1
  190. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  191. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  192. data/lib/graphql/schema/validator.rb +3 -1
  193. data/lib/graphql/schema/visibility/migration.rb +188 -0
  194. data/lib/graphql/schema/visibility/profile.rb +445 -0
  195. data/lib/graphql/schema/visibility/visit.rb +190 -0
  196. data/lib/graphql/schema/visibility.rb +311 -0
  197. data/lib/graphql/schema/warden.rb +275 -103
  198. data/lib/graphql/schema.rb +950 -210
  199. data/lib/graphql/static_validation/all_rules.rb +3 -3
  200. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  201. data/lib/graphql/static_validation/literal_validator.rb +6 -7
  202. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  203. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  204. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  205. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  206. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  207. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  208. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  209. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  210. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  211. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  212. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  213. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  214. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  215. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  216. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  217. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  218. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  219. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  220. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  221. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  222. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  223. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  224. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  225. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  226. data/lib/graphql/static_validation/validation_context.rb +21 -5
  227. data/lib/graphql/static_validation/validator.rb +9 -1
  228. data/lib/graphql/static_validation.rb +0 -1
  229. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
  230. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  231. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  232. data/lib/graphql/subscriptions/event.rb +21 -4
  233. data/lib/graphql/subscriptions/serialize.rb +3 -1
  234. data/lib/graphql/subscriptions.rb +21 -17
  235. data/lib/graphql/testing/helpers.rb +161 -0
  236. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  237. data/lib/graphql/testing.rb +3 -0
  238. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  239. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  240. data/lib/graphql/tracing/appoptics_trace.rb +7 -3
  241. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  242. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  243. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  244. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  245. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  246. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  247. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  248. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  249. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  250. data/lib/graphql/tracing/detailed_trace.rb +156 -0
  251. data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
  252. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  253. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  254. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  255. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  256. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  257. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  258. data/lib/graphql/tracing/null_trace.rb +9 -0
  259. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  260. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  261. data/lib/graphql/tracing/perfetto_trace.rb +864 -0
  262. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  263. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
  264. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  265. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  266. data/lib/graphql/tracing/scout_trace.rb +32 -58
  267. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  268. data/lib/graphql/tracing/sentry_trace.rb +82 -0
  269. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  270. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  271. data/lib/graphql/tracing/trace.rb +112 -1
  272. data/lib/graphql/tracing.rb +31 -28
  273. data/lib/graphql/type_kinds.rb +2 -1
  274. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  275. data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
  276. data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
  277. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  278. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  279. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  280. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  281. data/lib/graphql/types.rb +18 -10
  282. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  283. data/lib/graphql/unauthorized_error.rb +5 -1
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +71 -54
  286. data/readme.md +12 -2
  287. metadata +233 -37
  288. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  289. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  290. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  291. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  292. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  293. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  294. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  295. data/lib/graphql/analysis/ast.rb +0 -81
  296. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  297. data/lib/graphql/backtrace/trace.rb +0 -96
  298. data/lib/graphql/backtrace/tracer.rb +0 -80
  299. data/lib/graphql/deprecation.rb +0 -9
  300. data/lib/graphql/filter.rb +0 -59
  301. data/lib/graphql/language/parser.y +0 -560
  302. data/lib/graphql/language/token.rb +0 -34
  303. data/lib/graphql/schema/base_64_bp.rb +0 -26
  304. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  305. data/lib/graphql/schema/null_mask.rb +0 -11
  306. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  307. data/lib/graphql/static_validation/type_stack.rb +0 -216
  308. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -4,37 +4,12 @@ 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 Hiding 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
15
  def self.from_context(context)
@@ -44,6 +19,17 @@ module GraphQL
44
19
  PassThruWarden
45
20
  end
46
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
+
47
33
  # @param visibility_method [Symbol] a Warden method to call for this entry
48
34
  # @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
49
35
  # @param context [GraphQL::Query::Context]
@@ -85,23 +71,34 @@ module GraphQL
85
71
  def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
86
72
  def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
87
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
88
79
  end
89
80
  end
90
81
 
91
82
  class NullWarden
92
83
  def initialize(_filter = nil, context:, schema:)
93
84
  @schema = schema
85
+ @visibility_profile = Warden::VisibilityProfile.new(self)
94
86
  end
95
87
 
88
+ # No-op, but for compatibility:
89
+ attr_writer :skip_warning
90
+
91
+ attr_reader :visibility_profile
92
+
96
93
  def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
97
94
  def visible_argument?(arg_defn, _ctx = nil); true; end
98
95
  def visible_type?(type_defn, _ctx = nil); true; end
99
- def visible_enum_value?(enum_value, _ctx = nil); true; end
96
+ def visible_enum_value?(enum_value, _ctx = nil); enum_value.visible?(Query::NullContext.instance); end
100
97
  def visible_type_membership?(type_membership, _ctx = nil); true; end
101
98
  def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
102
- def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
99
+ def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
103
100
  def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
104
- def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
101
+ def enum_values(enum_defn); enum_defn.enum_values(Query::NullContext.instance); end # rubocop:disable Development/ContextIsPassedCop
105
102
  def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
106
103
  def types; @schema.types; end # rubocop:disable Development/ContextIsPassedCop
107
104
  def root_type_for_operation(op_name); @schema.root_type_for_operation(op_name); end
@@ -109,37 +106,117 @@ module GraphQL
109
106
  def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
110
107
  def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
111
108
  def reachable_type?(type_name); true; end
109
+ def loadable?(type, _ctx); true; end
110
+ def loadable_possible_types(abstract_type, _ctx); union_type.possible_types; end
112
111
  def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
113
- def possible_types(type_defn); @schema.possible_types(type_defn); end
112
+ def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
114
113
  def interfaces(obj_type); obj_type.interfaces; end
115
114
  end
116
115
 
117
- # @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
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
+
118
198
  # @param context [GraphQL::Query::Context]
119
199
  # @param schema [GraphQL::Schema]
120
- def initialize(filter = nil, context:, schema:)
200
+ def initialize(context:, schema:)
121
201
  @schema = schema
122
202
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
123
203
  @query = @schema.query
124
204
  @mutation = @schema.mutation
125
205
  @subscription = @schema.subscription
126
206
  @context = context
127
- @visibility_cache = if filter
128
- read_through { |m| filter.call(m, context) }
129
- else
130
- read_through { |m| schema.visible?(m, context) }
131
- end
132
-
133
- @visibility_cache.compare_by_identity
207
+ @visibility_cache = read_through { |m| check_visible(schema, m) }
134
208
  # Initialize all ivars to improve object shape consistency:
135
209
  @types = @visible_types = @reachable_types = @visible_parent_fields =
136
210
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
137
211
  @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
138
- @visible_and_reachable_type = @unions = @unfiltered_interfaces = @references_to =
139
- @reachable_type_set =
212
+ @visible_and_reachable_type = @unions = @unfiltered_interfaces =
213
+ @reachable_type_set = @visibility_profile = @loadable_possible_types =
140
214
  nil
215
+ @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
141
216
  end
142
217
 
218
+ attr_writer :skip_warning
219
+
143
220
  # @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
144
221
  def types
145
222
  @types ||= begin
@@ -153,10 +230,30 @@ module GraphQL
153
230
  end
154
231
  end
155
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
+ visible_type?(type) &&
236
+ !referenced?(type) &&
237
+ (type.respond_to?(:interfaces) ? interfaces(type).all? { |i| loadable?(i, _ctx) } : true)
238
+ end
239
+
240
+ # This abstract type was determined to be used for `loads` only.
241
+ # All its possible types are valid possibilities here -- no filtering.
242
+ def loadable_possible_types(abstract_type, _ctx)
243
+ @loadable_possible_types ||= read_through do |t|
244
+ if t.is_a?(Class) # union
245
+ t.possible_types
246
+ else
247
+ @schema.possible_types(abstract_type)
248
+ end
249
+ end
250
+ @loadable_possible_types[abstract_type]
251
+ end
252
+
156
253
  # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
157
254
  def get_type(type_name)
158
255
  @visible_types ||= read_through do |name|
159
- type_defn = @schema.get_type(name, @context)
256
+ type_defn = @schema.get_type(name, @context, false)
160
257
  if type_defn && visible_and_reachable_type?(type_defn)
161
258
  type_defn
162
259
  else
@@ -203,7 +300,7 @@ module GraphQL
203
300
  # @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
204
301
  def possible_types(type_defn)
205
302
  @visible_possible_types ||= read_through { |type_defn|
206
- pt = @schema.possible_types(type_defn, @context)
303
+ pt = @schema.possible_types(type_defn, @context, false)
207
304
  pt.select { |t| visible_and_reachable_type?(t) }
208
305
  }
209
306
  @visible_possible_types[type_defn]
@@ -219,7 +316,16 @@ module GraphQL
219
316
  # @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
220
317
  # @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
221
318
  def arguments(argument_owner, ctx = nil)
222
- @visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
319
+ @visible_arguments ||= read_through { |o|
320
+ args = o.arguments(@context)
321
+ if !args.empty?
322
+ args = args.values
323
+ args.select! { |a| visible_argument?(a, @context) }
324
+ args
325
+ else
326
+ EmptyObjects::EMPTY_ARRAY
327
+ end
328
+ }
223
329
  @visible_arguments[argument_owner]
224
330
  end
225
331
 
@@ -242,7 +348,13 @@ module GraphQL
242
348
 
243
349
  # @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
244
350
  def interfaces(obj_type)
245
- @visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
351
+ @visible_interfaces ||= read_through { |t|
352
+ ints = t.interfaces(@context)
353
+ if !ints.empty?
354
+ ints.select! { |i| visible_type?(i) }
355
+ end
356
+ ints
357
+ }
246
358
  @visible_interfaces[obj_type]
247
359
  end
248
360
 
@@ -298,11 +410,26 @@ module GraphQL
298
410
  next true if root_type?(type_defn) || type_defn.introspection?
299
411
 
300
412
  if type_defn.kind.union?
301
- visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
413
+ !possible_types(type_defn).empty? && (referenced?(type_defn) || orphan_type?(type_defn))
302
414
  elsif type_defn.kind.interface?
303
- visible_possible_types?(type_defn)
415
+ if !possible_types(type_defn).empty?
416
+ true
417
+ else
418
+ if @context.respond_to?(:logger) && (logger = @context.logger)
419
+ logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementers" }
420
+ end
421
+ false
422
+ end
304
423
  else
305
- referenced?(type_defn) || visible_abstract_type?(type_defn)
424
+ if referenced?(type_defn)
425
+ true
426
+ elsif type_defn.kind.object?
427
+ # Show this object if it belongs to ...
428
+ interfaces(type_defn).any? { |t| referenced?(t) } || # an interface which is referenced in the schema
429
+ union_memberships(type_defn).any? { |t| referenced?(t) || orphan_type?(t) } # or a union which is referenced or added via orphan_types
430
+ else
431
+ false
432
+ end
306
433
  end
307
434
  end
308
435
 
@@ -357,37 +484,74 @@ module GraphQL
357
484
  end
358
485
 
359
486
  def referenced?(type_defn)
360
- @references_to ||= @schema.references_to
361
- graphql_name = type_defn.unwrap.graphql_name
362
- members = @references_to[graphql_name] || NO_REFERENCES
487
+ members = @schema.references_to(type_defn)
363
488
  members.any? { |m| visible?(m) }
364
489
  end
365
490
 
366
- NO_REFERENCES = [].freeze
367
-
368
491
  def orphan_type?(type_defn)
369
492
  @schema.orphan_types.include?(type_defn)
370
493
  end
371
494
 
372
- def visible_abstract_type?(type_defn)
373
- type_defn.kind.object? && (
374
- interfaces(type_defn).any? ||
375
- union_memberships(type_defn).any?
376
- )
377
- end
378
-
379
- def visible_possible_types?(type_defn)
380
- possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
381
- end
382
-
383
495
  def visible?(member)
384
496
  @visibility_cache[member]
385
497
  end
386
498
 
387
499
  def read_through
388
- Hash.new { |h, k| h[k] = yield(k) }
500
+ Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
389
501
  end
390
502
 
503
+ def check_visible(schema, member)
504
+ if schema.visible?(member, @context)
505
+ true
506
+ elsif @skip_warning
507
+ false
508
+ else
509
+ member_s = member.respond_to?(:path) ? member.path : member.inspect
510
+ member_type = case member
511
+ when Module
512
+ if member.respond_to?(:kind)
513
+ member.kind.name.downcase
514
+ else
515
+ ""
516
+ end
517
+ when GraphQL::Schema::Field
518
+ "field"
519
+ when GraphQL::Schema::EnumValue
520
+ "enum value"
521
+ when GraphQL::Schema::Argument
522
+ "argument"
523
+ else
524
+ ""
525
+ end
526
+
527
+ schema_s = schema.name ? "#{schema.name}'s" : ""
528
+ schema_name = schema.name ? "#{schema.name}" : "your schema"
529
+ warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
530
+ @skip_warning = true # only warn once per query
531
+ # If there's no schema name, add the backtrace for additional context:
532
+ if schema_s == ""
533
+ puts caller.map { |l| " #{l}"}
534
+ end
535
+ false
536
+ end
537
+ end
538
+
539
+ ADD_WARDEN_WARNING = <<~WARNING
540
+ DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
541
+
542
+ Address this warning by adding:
543
+
544
+ use GraphQL::Schema::Visibility
545
+
546
+ to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
547
+
548
+ Alternatively, for legacy behavior, add:
549
+
550
+ use GraphQL::Schema::Warden # legacy visibility behavior
551
+
552
+ For more information see: https://graphql-ruby.org/authorization/visibility.html
553
+ WARNING
554
+
391
555
  def reachable_type_set
392
556
  return @reachable_type_set if @reachable_type_set
393
557
 
@@ -416,54 +580,62 @@ module GraphQL
416
580
  end
417
581
  end
418
582
 
583
+ included_interface_possible_types_set = Set.new
584
+
419
585
  until unvisited_types.empty?
420
586
  type = unvisited_types.pop
421
- if @reachable_type_set.add?(type)
422
- type_by_name = rt_hash[type.graphql_name] ||= type
423
- if type_by_name != type
424
- raise DuplicateNamesError.new(
425
- duplicated_name: type.graphql_name, duplicated_definition_1: type.inspect, duplicated_definition_2: type_by_name.inspect
426
- )
587
+ visit_type(type, unvisited_types, @reachable_type_set, rt_hash, included_interface_possible_types_set, include_interface_possible_types: false)
588
+ end
589
+
590
+ @reachable_type_set
591
+ end
592
+
593
+ def visit_type(type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types:)
594
+ if visited_type_set.add?(type) || (include_interface_possible_types && type.kind.interface? && included_interface_possible_types_set.add?(type))
595
+ type_by_name = type_by_name_hash[type.graphql_name] ||= type
596
+ if type_by_name != type
597
+ name_1, name_2 = [type.inspect, type_by_name.inspect].sort
598
+ raise DuplicateNamesError.new(
599
+ duplicated_name: type.graphql_name, duplicated_definition_1: name_1, duplicated_definition_2: name_2
600
+ )
601
+ end
602
+ if type.kind.input_object?
603
+ # recurse into visible arguments
604
+ arguments(type).each do |argument|
605
+ argument_type = argument.type.unwrap
606
+ unvisited_types << argument_type
427
607
  end
428
- if type.kind.input_object?
429
- # recurse into visible arguments
430
- arguments(type).each do |argument|
431
- argument_type = argument.type.unwrap
432
- unvisited_types << argument_type
433
- end
434
- elsif type.kind.union?
435
- # recurse into visible possible types
436
- possible_types(type).each do |possible_type|
437
- unvisited_types << possible_type
608
+ elsif type.kind.union?
609
+ # recurse into visible possible types
610
+ possible_types(type).each do |possible_type|
611
+ unvisited_types << possible_type
612
+ end
613
+ elsif type.kind.fields?
614
+ if type.kind.object?
615
+ # recurse into visible implemented interfaces
616
+ interfaces(type).each do |interface|
617
+ unvisited_types << interface
438
618
  end
439
- elsif type.kind.fields?
440
- if type.kind.interface?
441
- # recurse into visible possible types
442
- possible_types(type).each do |possible_type|
443
- unvisited_types << possible_type
444
- end
445
- elsif type.kind.object?
446
- # recurse into visible implemented interfaces
447
- interfaces(type).each do |interface|
448
- unvisited_types << interface
449
- end
619
+ elsif include_interface_possible_types
620
+ possible_types(type).each do |pt|
621
+ unvisited_types << pt
450
622
  end
623
+ end
624
+ # Don't visit interface possible types -- it's not enough to justify visibility
451
625
 
452
- # recurse into visible fields
453
- fields(type).each do |field|
454
- field_type = field.type.unwrap
455
- unvisited_types << field_type
456
- # recurse into visible arguments
457
- arguments(field).each do |argument|
458
- argument_type = argument.type.unwrap
459
- unvisited_types << argument_type
460
- end
626
+ # recurse into visible fields
627
+ fields(type).each do |field|
628
+ field_type = field.type.unwrap
629
+ # In this case, if it's an interface, we want to include
630
+ visit_type(field_type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types: true)
631
+ # recurse into visible arguments
632
+ arguments(field).each do |argument|
633
+ argument_type = argument.type.unwrap
634
+ unvisited_types << argument_type
461
635
  end
462
636
  end
463
637
  end
464
638
  end
465
-
466
- @reachable_type_set
467
639
  end
468
640
  end
469
641
  end