graphql 2.0.31 → 2.5.18

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 (287) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +49 -0
  6. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  7. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  8. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  9. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  10. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  11. data/lib/generators/graphql/templates/base_field.erb +2 -0
  12. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  13. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  14. data/lib/generators/graphql/templates/base_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  16. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  17. data/lib/generators/graphql/templates/base_union.erb +2 -0
  18. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  19. data/lib/generators/graphql/templates/loader.erb +2 -0
  20. data/lib/generators/graphql/templates/mutation.erb +2 -0
  21. data/lib/generators/graphql/templates/node_type.erb +2 -0
  22. data/lib/generators/graphql/templates/query_type.erb +2 -0
  23. data/lib/generators/graphql/templates/schema.erb +5 -0
  24. data/lib/generators/graphql/type_generator.rb +1 -1
  25. data/lib/graphql/analysis/analyzer.rb +90 -0
  26. data/lib/graphql/analysis/field_usage.rb +82 -0
  27. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  28. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  29. data/lib/graphql/analysis/query_complexity.rb +263 -0
  30. data/lib/graphql/analysis/query_depth.rb +58 -0
  31. data/lib/graphql/analysis/visitor.rb +280 -0
  32. data/lib/graphql/analysis.rb +95 -1
  33. data/lib/graphql/autoload.rb +38 -0
  34. data/lib/graphql/backtrace/table.rb +118 -55
  35. data/lib/graphql/backtrace.rb +1 -19
  36. data/lib/graphql/coercion_error.rb +1 -9
  37. data/lib/graphql/current.rb +57 -0
  38. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  39. data/lib/graphql/dashboard/installable.rb +22 -0
  40. data/lib/graphql/dashboard/limiters.rb +93 -0
  41. data/lib/graphql/dashboard/operation_store.rb +199 -0
  42. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  43. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  44. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  45. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  46. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  47. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  48. data/lib/graphql/dashboard/statics/icon.png +0 -0
  49. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  50. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  51. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  52. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  53. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  54. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  65. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  66. data/lib/graphql/dashboard.rb +161 -0
  67. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  68. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  69. data/lib/graphql/dataloader/async_dataloader.rb +112 -0
  70. data/lib/graphql/dataloader/null_dataloader.rb +51 -10
  71. data/lib/graphql/dataloader/request.rb +5 -0
  72. data/lib/graphql/dataloader/source.rb +35 -12
  73. data/lib/graphql/dataloader.rb +224 -149
  74. data/lib/graphql/date_encoding_error.rb +1 -1
  75. data/lib/graphql/dig.rb +2 -1
  76. data/lib/graphql/duration_encoding_error.rb +16 -0
  77. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  78. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  79. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  80. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
  81. data/lib/graphql/execution/interpreter/runtime.rb +363 -434
  82. data/lib/graphql/execution/interpreter.rb +91 -164
  83. data/lib/graphql/execution/lookahead.rb +105 -31
  84. data/lib/graphql/execution/multiplex.rb +6 -5
  85. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  86. data/lib/graphql/introspection/directive_type.rb +1 -1
  87. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  88. data/lib/graphql/introspection/entry_points.rb +11 -5
  89. data/lib/graphql/introspection/field_type.rb +1 -1
  90. data/lib/graphql/introspection/schema_type.rb +8 -11
  91. data/lib/graphql/introspection/type_type.rb +5 -5
  92. data/lib/graphql/invalid_name_error.rb +1 -1
  93. data/lib/graphql/invalid_null_error.rb +20 -17
  94. data/lib/graphql/language/block_string.rb +34 -18
  95. data/lib/graphql/language/cache.rb +13 -0
  96. data/lib/graphql/language/comment.rb +18 -0
  97. data/lib/graphql/language/definition_slice.rb +1 -1
  98. data/lib/graphql/language/document_from_schema_definition.rb +90 -61
  99. data/lib/graphql/language/lexer.rb +319 -193
  100. data/lib/graphql/language/nodes.rb +139 -77
  101. data/lib/graphql/language/parser.rb +807 -1985
  102. data/lib/graphql/language/printer.rb +324 -151
  103. data/lib/graphql/language/sanitized_printer.rb +21 -23
  104. data/lib/graphql/language/static_visitor.rb +171 -0
  105. data/lib/graphql/language/visitor.rb +62 -119
  106. data/lib/graphql/language.rb +71 -1
  107. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  108. data/lib/graphql/pagination/array_connection.rb +6 -6
  109. data/lib/graphql/pagination/connection.rb +28 -1
  110. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  111. data/lib/graphql/query/context/scoped_context.rb +101 -0
  112. data/lib/graphql/query/context.rb +81 -144
  113. data/lib/graphql/query/null_context.rb +7 -16
  114. data/lib/graphql/query/partial.rb +179 -0
  115. data/lib/graphql/query/validation_pipeline.rb +4 -4
  116. data/lib/graphql/query/variable_validation_error.rb +1 -1
  117. data/lib/graphql/query/variables.rb +3 -3
  118. data/lib/graphql/query.rb +126 -81
  119. data/lib/graphql/railtie.rb +16 -6
  120. data/lib/graphql/rake_task.rb +3 -12
  121. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  122. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  123. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  124. data/lib/graphql/rubocop.rb +2 -0
  125. data/lib/graphql/schema/addition.rb +26 -13
  126. data/lib/graphql/schema/always_visible.rb +7 -2
  127. data/lib/graphql/schema/argument.rb +73 -14
  128. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  129. data/lib/graphql/schema/build_from_definition.rb +123 -66
  130. data/lib/graphql/schema/directive/flagged.rb +4 -2
  131. data/lib/graphql/schema/directive/one_of.rb +12 -0
  132. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  133. data/lib/graphql/schema/directive.rb +55 -3
  134. data/lib/graphql/schema/enum.rb +110 -27
  135. data/lib/graphql/schema/enum_value.rb +11 -3
  136. data/lib/graphql/schema/field/connection_extension.rb +2 -16
  137. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  138. data/lib/graphql/schema/field.rb +173 -119
  139. data/lib/graphql/schema/field_extension.rb +1 -1
  140. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  141. data/lib/graphql/schema/input_object.rb +123 -65
  142. data/lib/graphql/schema/interface.rb +34 -16
  143. data/lib/graphql/schema/introspection_system.rb +8 -17
  144. data/lib/graphql/schema/late_bound_type.rb +4 -0
  145. data/lib/graphql/schema/list.rb +3 -3
  146. data/lib/graphql/schema/loader.rb +3 -4
  147. data/lib/graphql/schema/member/base_dsl_methods.rb +17 -1
  148. data/lib/graphql/schema/member/has_arguments.rb +132 -100
  149. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  150. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  151. data/lib/graphql/schema/member/has_directives.rb +5 -5
  152. data/lib/graphql/schema/member/has_fields.rb +111 -16
  153. data/lib/graphql/schema/member/has_interfaces.rb +27 -13
  154. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  155. data/lib/graphql/schema/member/has_validators.rb +1 -1
  156. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  157. data/lib/graphql/schema/member/scoped.rb +19 -0
  158. data/lib/graphql/schema/member/type_system_helpers.rb +18 -5
  159. data/lib/graphql/schema/member/validates_input.rb +3 -3
  160. data/lib/graphql/schema/member.rb +1 -0
  161. data/lib/graphql/schema/mutation.rb +7 -0
  162. data/lib/graphql/schema/object.rb +33 -8
  163. data/lib/graphql/schema/printer.rb +9 -7
  164. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  165. data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
  166. data/lib/graphql/schema/resolver.rb +45 -31
  167. data/lib/graphql/schema/scalar.rb +4 -9
  168. data/lib/graphql/schema/subscription.rb +63 -10
  169. data/lib/graphql/schema/timeout.rb +19 -2
  170. data/lib/graphql/schema/type_expression.rb +2 -2
  171. data/lib/graphql/schema/union.rb +2 -2
  172. data/lib/graphql/schema/unique_within_type.rb +1 -1
  173. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  174. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  175. data/lib/graphql/schema/validator.rb +3 -1
  176. data/lib/graphql/schema/visibility/migration.rb +188 -0
  177. data/lib/graphql/schema/visibility/profile.rb +445 -0
  178. data/lib/graphql/schema/visibility/visit.rb +190 -0
  179. data/lib/graphql/schema/visibility.rb +311 -0
  180. data/lib/graphql/schema/warden.rb +275 -103
  181. data/lib/graphql/schema.rb +924 -210
  182. data/lib/graphql/static_validation/all_rules.rb +3 -3
  183. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  184. data/lib/graphql/static_validation/literal_validator.rb +6 -7
  185. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  186. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  187. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  188. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  189. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  190. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  191. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  192. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  193. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  194. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  195. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  196. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  197. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  198. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  199. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  200. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  201. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  202. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  203. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  204. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  205. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  206. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  207. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  208. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  209. data/lib/graphql/static_validation/validation_context.rb +21 -5
  210. data/lib/graphql/static_validation/validator.rb +9 -1
  211. data/lib/graphql/static_validation.rb +0 -1
  212. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
  213. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  214. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  215. data/lib/graphql/subscriptions/event.rb +21 -4
  216. data/lib/graphql/subscriptions/serialize.rb +3 -1
  217. data/lib/graphql/subscriptions.rb +21 -17
  218. data/lib/graphql/testing/helpers.rb +161 -0
  219. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  220. data/lib/graphql/testing.rb +3 -0
  221. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  222. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  223. data/lib/graphql/tracing/appoptics_trace.rb +11 -3
  224. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  225. data/lib/graphql/tracing/appsignal_trace.rb +32 -55
  226. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  227. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  228. data/lib/graphql/tracing/data_dog_trace.rb +46 -158
  229. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  230. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  231. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  232. data/lib/graphql/tracing/detailed_trace.rb +141 -0
  233. data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
  234. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  235. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  236. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  237. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  238. data/lib/graphql/tracing/notifications_trace.rb +184 -34
  239. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  240. data/lib/graphql/tracing/null_trace.rb +9 -0
  241. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  242. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  243. data/lib/graphql/tracing/perfetto_trace.rb +818 -0
  244. data/lib/graphql/tracing/platform_trace.rb +5 -0
  245. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  246. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
  247. data/lib/graphql/tracing/prometheus_trace.rb +72 -68
  248. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  249. data/lib/graphql/tracing/scout_trace.rb +32 -55
  250. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  251. data/lib/graphql/tracing/sentry_trace.rb +82 -0
  252. data/lib/graphql/tracing/statsd_trace.rb +33 -41
  253. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  254. data/lib/graphql/tracing/trace.rb +112 -1
  255. data/lib/graphql/tracing.rb +31 -28
  256. data/lib/graphql/type_kinds.rb +2 -1
  257. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  258. data/lib/graphql/types/relay/connection_behaviors.rb +43 -3
  259. data/lib/graphql/types/relay/edge_behaviors.rb +18 -1
  260. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  261. data/lib/graphql/types.rb +18 -10
  262. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  263. data/lib/graphql/version.rb +1 -1
  264. data/lib/graphql.rb +68 -54
  265. data/readme.md +12 -2
  266. metadata +220 -40
  267. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  268. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  269. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  270. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  271. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  272. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  273. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  274. data/lib/graphql/analysis/ast.rb +0 -81
  275. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  276. data/lib/graphql/backtrace/trace.rb +0 -96
  277. data/lib/graphql/backtrace/tracer.rb +0 -80
  278. data/lib/graphql/deprecation.rb +0 -9
  279. data/lib/graphql/filter.rb +0 -59
  280. data/lib/graphql/language/parser.y +0 -560
  281. data/lib/graphql/language/token.rb +0 -34
  282. data/lib/graphql/schema/base_64_bp.rb +0 -26
  283. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  284. data/lib/graphql/schema/null_mask.rb +0 -11
  285. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  286. data/lib/graphql/static_validation/type_stack.rb +0 -216
  287. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -10,6 +10,14 @@ module GraphQL
10
10
 
11
11
  include GraphQL::Dig
12
12
 
13
+ # Raised when an InputObject doesn't have any arguments defined and hasn't explicitly opted out of this requirement
14
+ class ArgumentsAreRequiredError < GraphQL::Error
15
+ def initialize(input_object_type)
16
+ message = "Input Object types must have arguments, but #{input_object_type.graphql_name} doesn't have any. Define an argument for this type, remove it from your schema, or add `has_no_arguments(true)` to its definition."
17
+ super(message)
18
+ end
19
+ end
20
+
13
21
  # @return [GraphQL::Query::Context] The context for this query
14
22
  attr_reader :context
15
23
  # @return [GraphQL::Execution::Interpereter::Arguments] The underlying arguments instance
@@ -23,13 +31,14 @@ module GraphQL
23
31
  @ruby_style_hash = ruby_kwargs
24
32
  @arguments = arguments
25
33
  # Apply prepares, not great to have it duplicated here.
26
- self.class.arguments(context).each_value do |arg_defn|
34
+ arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
35
+ arg_defns.each do |arg_defn|
27
36
  ruby_kwargs_key = arg_defn.keyword
28
37
  if @ruby_style_hash.key?(ruby_kwargs_key)
29
38
  # Weirdly, procs are applied during coercion, but not methods.
30
39
  # Probably because these methods require a `self`.
31
40
  if arg_defn.prepare.is_a?(Symbol) || context.nil?
32
- prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
41
+ prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key], context: context)
33
42
  overwrite_argument(ruby_kwargs_key, prepared_value)
34
43
  end
35
44
  end
@@ -44,42 +53,18 @@ module GraphQL
44
53
  to_h
45
54
  end
46
55
 
47
- def prepare
48
- if @context
49
- object = @context[:current_object]
50
- # Pass this object's class with `as` so that messages are rendered correctly from inherited validators
51
- Schema::Validator.validate!(self.class.validators, object, @context, @ruby_style_hash, as: self.class)
52
- self
56
+ def deconstruct_keys(keys = nil)
57
+ if keys.nil?
58
+ @ruby_style_hash
53
59
  else
54
- self
60
+ new_h = {}
61
+ keys.each { |k| @ruby_style_hash.key?(k) && new_h[k] = @ruby_style_hash[k] }
62
+ new_h
55
63
  end
56
64
  end
57
65
 
58
- def self.authorized?(obj, value, ctx)
59
- # Authorize each argument (but this doesn't apply if `prepare` is implemented):
60
- if value.respond_to?(:key?)
61
- arguments(ctx).each do |_name, input_obj_arg|
62
- if value.key?(input_obj_arg.keyword) &&
63
- !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
64
- return false
65
- end
66
- end
67
- end
68
- # It didn't early-return false:
69
- true
70
- end
71
-
72
- def self.one_of
73
- if !one_of?
74
- if all_argument_definitions.any? { |arg| arg.type.non_null? }
75
- raise ArgumentError, "`one_of` may not be used with required arguments -- add `required: false` to argument definitions to use `one_of`"
76
- end
77
- directive(GraphQL::Schema::Directive::OneOf)
78
- end
79
- end
80
-
81
- def self.one_of?
82
- directives.any? { |d| d.is_a?(GraphQL::Schema::Directive::OneOf) }
66
+ def prepare
67
+ self
83
68
  end
84
69
 
85
70
  def unwrap_value(value)
@@ -119,7 +104,42 @@ module GraphQL
119
104
  @ruby_style_hash.dup
120
105
  end
121
106
 
107
+ # @api private
108
+ def validate_for(context)
109
+ object = context[:current_object]
110
+ # Pass this object's class with `as` so that messages are rendered correctly from inherited validators
111
+ Schema::Validator.validate!(self.class.validators, object, context, @ruby_style_hash, as: self.class)
112
+ nil
113
+ end
114
+
122
115
  class << self
116
+ def authorized?(obj, value, ctx)
117
+ # Authorize each argument (but this doesn't apply if `prepare` is implemented):
118
+ if value.respond_to?(:key?)
119
+ ctx.types.arguments(self).each do |input_obj_arg|
120
+ if value.key?(input_obj_arg.keyword) &&
121
+ !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
122
+ return false
123
+ end
124
+ end
125
+ end
126
+ # It didn't early-return false:
127
+ true
128
+ end
129
+
130
+ def one_of
131
+ if !one_of?
132
+ if all_argument_definitions.any? { |arg| arg.type.non_null? }
133
+ raise ArgumentError, "`one_of` may not be used with required arguments -- add `required: false` to argument definitions to use `one_of`"
134
+ end
135
+ directive(GraphQL::Schema::Directive::OneOf)
136
+ end
137
+ end
138
+
139
+ def one_of?
140
+ false # Re-defined when `OneOf` is added
141
+ end
142
+
123
143
  def argument(*args, **kwargs, &block)
124
144
  argument_defn = super(*args, **kwargs, &block)
125
145
  if one_of?
@@ -131,12 +151,9 @@ module GraphQL
131
151
  end
132
152
  end
133
153
  # Add a method access
134
- method_name = argument_defn.keyword
135
- class_eval <<-RUBY, __FILE__, __LINE__
136
- def #{method_name}
137
- self[#{method_name.inspect}]
138
- end
139
- RUBY
154
+ suppress_redefinition_warning do
155
+ define_accessor_method(argument_defn.keyword)
156
+ end
140
157
  argument_defn
141
158
  end
142
159
 
@@ -145,10 +162,10 @@ module GraphQL
145
162
  end
146
163
 
147
164
  # @api private
148
- INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
165
+ INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
149
166
 
150
167
  def validate_non_null_input(input, ctx, max_errors: nil)
151
- warden = ctx.warden
168
+ types = ctx.types
152
169
 
153
170
  if input.is_a?(Array)
154
171
  return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
@@ -159,30 +176,37 @@ module GraphQL
159
176
  return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
160
177
  end
161
178
 
162
- # Inject missing required arguments
163
- missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
164
- if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
165
- m[argument_name] = nil
166
- end
167
-
168
- m
169
- end
170
179
 
171
180
  result = nil
172
- [input, missing_required_inputs].each do |args_to_validate|
173
- args_to_validate.each do |argument_name, value|
174
- argument = warden.get_argument(self, argument_name)
175
- # Items in the input that are unexpected
176
- if argument.nil?
177
- result ||= Query::InputValidationResult.new
178
- result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
179
- else
180
- # Items in the input that are expected, but have invalid values
181
- argument_result = argument.type.validate_input(value, ctx)
181
+
182
+
183
+ input.each do |argument_name, value|
184
+ argument = types.argument(self, argument_name)
185
+ if argument.nil? && ctx.is_a?(Query::NullContext) && argument_name.is_a?(Symbol)
186
+ # Validating definition directive arguments which come in as Symbols
187
+ argument = types.arguments(self).find { |arg| arg.keyword == argument_name }
188
+ end
189
+ # Items in the input that are unexpected
190
+ if argument.nil?
191
+ result ||= Query::InputValidationResult.new
192
+ result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
193
+ else
194
+ # Items in the input that are expected, but have invalid values
195
+ argument_result = argument.type.validate_input(value, ctx)
196
+ if !argument_result.valid?
182
197
  result ||= Query::InputValidationResult.new
183
- if !argument_result.valid?
184
- result.merge_result!(argument_name, argument_result)
185
- end
198
+ result.merge_result!(argument_name, argument_result)
199
+ end
200
+ end
201
+ end
202
+
203
+ # Check for missing non-null arguments
204
+ ctx.types.arguments(self).each do |argument|
205
+ if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value?
206
+ result ||= Query::InputValidationResult.new
207
+ argument_result = argument.type.validate_input(nil, ctx)
208
+ if !argument_result.valid?
209
+ result.merge_result!(argument.graphql_name, argument_result)
186
210
  end
187
211
  end
188
212
  end
@@ -215,8 +239,7 @@ module GraphQL
215
239
  if resolved_arguments.is_a?(GraphQL::Error)
216
240
  raise resolved_arguments
217
241
  else
218
- input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
219
- input_obj_instance.prepare
242
+ self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
220
243
  end
221
244
  end
222
245
  end
@@ -242,6 +265,41 @@ module GraphQL
242
265
 
243
266
  result
244
267
  end
268
+
269
+ # @param new_has_no_arguments [Boolean] Call with `true` to make this InputObject type ignore the requirement to have any defined arguments.
270
+ # @return [void]
271
+ def has_no_arguments(new_has_no_arguments)
272
+ @has_no_arguments = new_has_no_arguments
273
+ nil
274
+ end
275
+
276
+ # @return [Boolean] `true` if `has_no_arguments(true)` was configued
277
+ def has_no_arguments?
278
+ @has_no_arguments
279
+ end
280
+
281
+ def arguments(context = GraphQL::Query::NullContext.instance, require_defined_arguments = true)
282
+ if require_defined_arguments && !has_no_arguments? && !any_arguments?
283
+ warn(GraphQL::Schema::InputObject::ArgumentsAreRequiredError.new(self).message + "\n\nThis will raise an error in a future GraphQL-Ruby version.")
284
+ end
285
+ super(context, false)
286
+ end
287
+
288
+ private
289
+
290
+ # Suppress redefinition warning for objectId arguments
291
+ def suppress_redefinition_warning
292
+ verbose = $VERBOSE
293
+ $VERBOSE = nil
294
+ yield
295
+ ensure
296
+ $VERBOSE = verbose
297
+ end
298
+
299
+ def define_accessor_method(method_name)
300
+ define_method(method_name) { self[method_name] }
301
+ alias_method(method_name, method_name)
302
+ end
245
303
  end
246
304
 
247
305
  private
@@ -13,6 +13,7 @@ module GraphQL
13
13
  include GraphQL::Schema::Member::Scoped
14
14
  include GraphQL::Schema::Member::HasAstNode
15
15
  include GraphQL::Schema::Member::HasUnresolvedTypeError
16
+ include GraphQL::Schema::Member::HasDataloader
16
17
  include GraphQL::Schema::Member::HasDirectives
17
18
  include GraphQL::Schema::Member::HasInterfaces
18
19
 
@@ -20,7 +21,16 @@ module GraphQL
20
21
  # - Added as class methods to this interface
21
22
  # - Added as class methods to all child interfaces
22
23
  def definition_methods(&block)
23
- self::DefinitionMethods.module_eval(&block)
24
+ # Use an instance variable to tell whether it's been included previously or not;
25
+ # You can't use constant detection because constants are brought into scope
26
+ # by `include`, which has already happened at this point.
27
+ if !defined?(@_definition_methods)
28
+ defn_methods_module = Module.new
29
+ @_definition_methods = defn_methods_module
30
+ const_set(:DefinitionMethods, defn_methods_module)
31
+ extend(self::DefinitionMethods)
32
+ end
33
+ self::DefinitionMethods.module_exec(&block)
24
34
  end
25
35
 
26
36
  # @see {Schema::Warden} hides interfaces without visible implementations
@@ -47,22 +57,14 @@ module GraphQL
47
57
 
48
58
  child_class.type_membership_class(self.type_membership_class)
49
59
  child_class.ancestors.reverse_each do |ancestor|
50
- if ancestor.const_defined?(:DefinitionMethods)
60
+ if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
51
61
  child_class.extend(ancestor::DefinitionMethods)
52
62
  end
53
63
  end
54
64
 
55
- # Use an instance variable to tell whether it's been included previously or not;
56
- # You can't use constant detection because constants are brought into scope
57
- # by `include`, which has already happened at this point.
58
- if !child_class.instance_variable_defined?(:@_definition_methods)
59
- defn_methods_module = Module.new
60
- child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
61
- child_class.const_set(:DefinitionMethods, defn_methods_module)
62
- child_class.extend(child_class::DefinitionMethods)
63
- end
64
65
  child_class.introspection(introspection)
65
66
  child_class.description(description)
67
+ child_class.comment(nil)
66
68
  # If interfaces are mixed into each other, only define this class once
67
69
  if !child_class.const_defined?(:UnresolvedTypeError, false)
68
70
  add_unresolved_type_error(child_class)
@@ -82,13 +84,29 @@ module GraphQL
82
84
  super
83
85
  end
84
86
 
87
+ # Register other Interface or Object types as implementers of this Interface.
88
+ #
89
+ # When those Interfaces or Objects aren't used as the return values of fields,
90
+ # they may have to be registered using this method so that GraphQL-Ruby can find them.
91
+ # @param types [Class, Module]
92
+ # @return [Array<Module, Class>] Implementers of this interface, if they're registered
85
93
  def orphan_types(*types)
86
- if types.any?
87
- @orphan_types = types
94
+ if !types.empty?
95
+ @orphan_types ||= []
96
+ @orphan_types.concat(types)
88
97
  else
89
- all_orphan_types = @orphan_types || []
90
- all_orphan_types += super if defined?(super)
91
- all_orphan_types.uniq
98
+ if defined?(@orphan_types)
99
+ all_orphan_types = @orphan_types.dup
100
+ if defined?(super)
101
+ all_orphan_types += super
102
+ all_orphan_types.uniq!
103
+ end
104
+ all_orphan_types
105
+ elsif defined?(super)
106
+ super
107
+ else
108
+ EmptyObjects::EMPTY_ARRAY
109
+ end
92
110
  end
93
111
  end
94
112
 
@@ -25,10 +25,10 @@ module GraphQL
25
25
  load_constant(:DirectiveLocationEnum)
26
26
  ]
27
27
  @types = {}
28
- @possible_types = {}
28
+ @possible_types = {}.compare_by_identity
29
29
  type_defns.each do |t|
30
30
  @types[t.graphql_name] = t
31
- @possible_types[t.graphql_name] = [t]
31
+ @possible_types[t] = [t]
32
32
  end
33
33
  @entry_point_fields =
34
34
  if schema.disable_introspection_entry_points?
@@ -39,7 +39,9 @@ module GraphQL
39
39
  entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
40
40
  entry_point_fields
41
41
  end
42
+ @entry_point_fields.each { |k, v| v.dynamic_introspection = true }
42
43
  @dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
44
+ @dynamic_fields.each { |k, v| v.dynamic_introspection = true }
43
45
  end
44
46
 
45
47
  def entry_points
@@ -67,7 +69,7 @@ module GraphQL
67
69
  def resolve_late_bindings
68
70
  @types.each do |name, t|
69
71
  if t.kind.fields?
70
- t.fields.each do |_name, field_defn|
72
+ t.all_field_definitions.each do |field_defn|
71
73
  field_defn.type = resolve_late_binding(field_defn.type)
72
74
  end
73
75
  end
@@ -88,7 +90,8 @@ module GraphQL
88
90
  def resolve_late_binding(late_bound_type)
89
91
  case late_bound_type
90
92
  when GraphQL::Schema::LateBoundType
91
- @schema.get_type(late_bound_type.name)
93
+ type_name = late_bound_type.name
94
+ @types[type_name] || @schema.get_type(type_name)
92
95
  when GraphQL::Schema::List
93
96
  resolve_late_binding(late_bound_type.of_type).to_list_type
94
97
  when GraphQL::Schema::NonNull
@@ -111,19 +114,7 @@ module GraphQL
111
114
 
112
115
  def get_fields_from_class(class_sym:)
113
116
  object_type_defn = load_constant(class_sym)
114
-
115
- if object_type_defn.is_a?(Module)
116
- object_type_defn.fields
117
- else
118
- extracted_field_defns = {}
119
- object_class = object_type_defn.metadata[:type_class]
120
- object_type_defn.all_fields.each do |field_defn|
121
- inner_resolve = field_defn.resolve_proc
122
- resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
123
- extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
124
- end
125
- extracted_field_defns
126
- end
117
+ object_type_defn.fields
127
118
  end
128
119
 
129
120
  # This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
@@ -25,6 +25,10 @@ module GraphQL
25
25
  @to_list_type ||= GraphQL::Schema::List.new(self)
26
26
  end
27
27
 
28
+ def to_type_signature
29
+ name
30
+ end
31
+
28
32
  def inspect
29
33
  "#<LateBoundType @name=#{name}>"
30
34
  end
@@ -4,7 +4,7 @@ module GraphQL
4
4
  class Schema
5
5
  # Represents a list type in the schema.
6
6
  # Wraps a {Schema::Member} as a list type.
7
- # @see {Schema::Member::TypeSystemHelpers#to_list_type}
7
+ # @see Schema::Member::TypeSystemHelpers#to_list_type Create a list type from another GraphQL type
8
8
  class List < GraphQL::Schema::Wrapper
9
9
  include Schema::Member::ValidatesInput
10
10
 
@@ -52,7 +52,7 @@ module GraphQL
52
52
  unless item_result.valid?
53
53
  if max_errors
54
54
  if max_errors == 0
55
- add_max_errros_reached_message(result)
55
+ add_max_errors_reached_message(result)
56
56
  break
57
57
  end
58
58
 
@@ -76,7 +76,7 @@ module GraphQL
76
76
  end
77
77
  end
78
78
 
79
- def add_max_errros_reached_message(result)
79
+ def add_max_errors_reached_message(result)
80
80
  message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
81
81
  item_result = GraphQL::Query::InputValidationResult.from_problem(message)
82
82
  result.merge_result!(nil, item_result)
@@ -32,7 +32,8 @@ module GraphQL
32
32
  end
33
33
 
34
34
  Class.new(GraphQL::Schema) do
35
- orphan_types(types.values)
35
+ add_type_and_traverse(types.values, root: false)
36
+ orphan_types(types.values.select { |t| t.kind.object? })
36
37
  directives(directives)
37
38
  description(schema["description"])
38
39
 
@@ -176,7 +177,6 @@ module GraphQL
176
177
  while (of_type = unwrapped_field_hash["ofType"])
177
178
  unwrapped_field_hash = of_type
178
179
  end
179
- type_name = unwrapped_field_hash["name"]
180
180
 
181
181
  type_defn.field(
182
182
  field_hash["name"],
@@ -186,9 +186,8 @@ module GraphQL
186
186
  null: true,
187
187
  camelize: false,
188
188
  connection_extension: nil,
189
- connection: type_name.end_with?("Connection"),
190
189
  ) do
191
- if field_hash["args"].any?
190
+ if !field_hash["args"].empty?
192
191
  loader.build_arguments(self, field_hash["args"], type_resolver)
193
192
  end
194
193
  end
@@ -50,12 +50,27 @@ module GraphQL
50
50
  end
51
51
  end
52
52
 
53
+ # Call this method to provide a new comment; OR
54
+ # call it without an argument to get the comment
55
+ # @param new_comment [String]
56
+ # @return [String, nil]
57
+ def comment(new_comment = NOT_CONFIGURED)
58
+ if !NOT_CONFIGURED.equal?(new_comment)
59
+ @comment = new_comment
60
+ elsif defined?(@comment)
61
+ @comment
62
+ else
63
+ nil
64
+ end
65
+ end
66
+
53
67
  # This pushes some configurations _down_ the inheritance tree,
54
68
  # in order to prevent repetitive lookups at runtime.
55
69
  module ConfigurationExtension
56
70
  def inherited(child_class)
57
71
  child_class.introspection(introspection)
58
72
  child_class.description(description)
73
+ child_class.comment(nil)
59
74
  child_class.default_graphql_name = nil
60
75
 
61
76
  if defined?(@graphql_name) && @graphql_name && (self.name.nil? || graphql_name != default_graphql_name)
@@ -102,7 +117,8 @@ module GraphQL
102
117
  def default_graphql_name
103
118
  @default_graphql_name ||= begin
104
119
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
105
- -name.split("::").last.sub(/Type\Z/, "")
120
+ g_name = -name.split("::").last
121
+ g_name.end_with?("Type") ? g_name.sub(/Type\Z/, "") : g_name
106
122
  end
107
123
  end
108
124