graphql 1.11.6 → 1.13.19

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 (293) 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/install_generator.rb +17 -7
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/loader_generator.rb +1 -0
  10. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_generator.rb +6 -30
  13. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  14. data/lib/generators/graphql/object_generator.rb +12 -38
  15. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  16. data/lib/generators/graphql/relay.rb +63 -0
  17. data/lib/generators/graphql/relay_generator.rb +21 -0
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  20. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  21. data/lib/generators/graphql/templates/enum.erb +5 -1
  22. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  23. data/lib/generators/graphql/templates/input.erb +9 -0
  24. data/lib/generators/graphql/templates/interface.erb +4 -2
  25. data/lib/generators/graphql/templates/mutation.erb +1 -1
  26. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  27. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  28. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  29. data/lib/generators/graphql/templates/node_type.erb +9 -0
  30. data/lib/generators/graphql/templates/object.erb +5 -3
  31. data/lib/generators/graphql/templates/query_type.erb +1 -3
  32. data/lib/generators/graphql/templates/scalar.erb +3 -1
  33. data/lib/generators/graphql/templates/schema.erb +19 -34
  34. data/lib/generators/graphql/templates/union.erb +4 -2
  35. data/lib/generators/graphql/type_generator.rb +47 -10
  36. data/lib/generators/graphql/union_generator.rb +5 -5
  37. data/lib/graphql/analysis/analyze_query.rb +7 -0
  38. data/lib/graphql/analysis/ast/field_usage.rb +28 -1
  39. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  40. data/lib/graphql/analysis/ast/visitor.rb +14 -5
  41. data/lib/graphql/analysis/ast.rb +11 -2
  42. data/lib/graphql/argument.rb +1 -1
  43. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  44. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  45. data/lib/graphql/backtrace/table.rb +34 -3
  46. data/lib/graphql/backtrace/traced_error.rb +0 -1
  47. data/lib/graphql/backtrace/tracer.rb +40 -10
  48. data/lib/graphql/backtrace.rb +28 -19
  49. data/lib/graphql/backwards_compatibility.rb +2 -1
  50. data/lib/graphql/base_type.rb +6 -4
  51. data/lib/graphql/boolean_type.rb +1 -1
  52. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  53. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  54. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  55. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  56. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  57. data/lib/graphql/dataloader/request.rb +19 -0
  58. data/lib/graphql/dataloader/request_all.rb +19 -0
  59. data/lib/graphql/dataloader/source.rb +155 -0
  60. data/lib/graphql/dataloader.rb +308 -0
  61. data/lib/graphql/date_encoding_error.rb +16 -0
  62. data/lib/graphql/define/assign_global_id_field.rb +1 -1
  63. data/lib/graphql/define/instance_definable.rb +48 -3
  64. data/lib/graphql/define/type_definer.rb +5 -5
  65. data/lib/graphql/deprecated_dsl.rb +18 -5
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  68. data/lib/graphql/directive/include_directive.rb +1 -1
  69. data/lib/graphql/directive/skip_directive.rb +1 -1
  70. data/lib/graphql/directive.rb +1 -5
  71. data/lib/graphql/enum_type.rb +9 -3
  72. data/lib/graphql/execution/errors.rb +110 -7
  73. data/lib/graphql/execution/execute.rb +8 -1
  74. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  75. data/lib/graphql/execution/interpreter/arguments_cache.rb +49 -15
  76. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  77. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  78. data/lib/graphql/execution/interpreter/runtime.rb +670 -294
  79. data/lib/graphql/execution/interpreter.rb +16 -16
  80. data/lib/graphql/execution/lazy.rb +5 -1
  81. data/lib/graphql/execution/lookahead.rb +2 -2
  82. data/lib/graphql/execution/multiplex.rb +39 -23
  83. data/lib/graphql/field.rb +1 -1
  84. data/lib/graphql/float_type.rb +1 -1
  85. data/lib/graphql/function.rb +4 -0
  86. data/lib/graphql/id_type.rb +1 -1
  87. data/lib/graphql/input_object_type.rb +3 -1
  88. data/lib/graphql/int_type.rb +1 -1
  89. data/lib/graphql/integer_decoding_error.rb +17 -0
  90. data/lib/graphql/integer_encoding_error.rb +18 -2
  91. data/lib/graphql/interface_type.rb +4 -2
  92. data/lib/graphql/internal_representation/document.rb +2 -2
  93. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  94. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  95. data/lib/graphql/introspection/directive_type.rb +11 -5
  96. data/lib/graphql/introspection/entry_points.rb +2 -2
  97. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  98. data/lib/graphql/introspection/field_type.rb +3 -3
  99. data/lib/graphql/introspection/input_value_type.rb +10 -4
  100. data/lib/graphql/introspection/schema_type.rb +10 -5
  101. data/lib/graphql/introspection/type_type.rb +18 -12
  102. data/lib/graphql/introspection.rb +5 -2
  103. data/lib/graphql/invalid_null_error.rb +1 -1
  104. data/lib/graphql/language/block_string.rb +2 -6
  105. data/lib/graphql/language/cache.rb +37 -0
  106. data/lib/graphql/language/document_from_schema_definition.rb +60 -26
  107. data/lib/graphql/language/lexer.rb +50 -28
  108. data/lib/graphql/language/lexer.rl +2 -4
  109. data/lib/graphql/language/nodes.rb +14 -4
  110. data/lib/graphql/language/parser.rb +856 -825
  111. data/lib/graphql/language/parser.y +28 -11
  112. data/lib/graphql/language/printer.rb +10 -1
  113. data/lib/graphql/language/sanitized_printer.rb +5 -5
  114. data/lib/graphql/language/token.rb +0 -4
  115. data/lib/graphql/language.rb +1 -0
  116. data/lib/graphql/name_validator.rb +0 -4
  117. data/lib/graphql/object_type.rb +4 -4
  118. data/lib/graphql/pagination/active_record_relation_connection.rb +47 -3
  119. data/lib/graphql/pagination/connection.rb +19 -1
  120. data/lib/graphql/pagination/connections.rb +45 -30
  121. data/lib/graphql/pagination/relation_connection.rb +69 -28
  122. data/lib/graphql/parse_error.rb +0 -1
  123. data/lib/graphql/query/arguments.rb +2 -2
  124. data/lib/graphql/query/arguments_cache.rb +1 -2
  125. data/lib/graphql/query/context.rb +22 -4
  126. data/lib/graphql/query/executor.rb +0 -1
  127. data/lib/graphql/query/input_validation_result.rb +9 -0
  128. data/lib/graphql/query/literal_input.rb +1 -1
  129. data/lib/graphql/query/null_context.rb +21 -9
  130. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  131. data/lib/graphql/query/serial_execution.rb +1 -0
  132. data/lib/graphql/query/validation_pipeline.rb +3 -4
  133. data/lib/graphql/query/variable_validation_error.rb +3 -3
  134. data/lib/graphql/query/variables.rb +35 -4
  135. data/lib/graphql/query.rb +20 -8
  136. data/lib/graphql/railtie.rb +9 -1
  137. data/lib/graphql/rake_task.rb +3 -0
  138. data/lib/graphql/relay/array_connection.rb +2 -2
  139. data/lib/graphql/relay/base_connection.rb +7 -0
  140. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  141. data/lib/graphql/relay/connection_type.rb +16 -3
  142. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  143. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  144. data/lib/graphql/relay/mutation.rb +2 -1
  145. data/lib/graphql/relay/node.rb +3 -0
  146. data/lib/graphql/relay/page_info.rb +1 -1
  147. data/lib/graphql/relay/range_add.rb +14 -5
  148. data/lib/graphql/relay/type_extensions.rb +2 -0
  149. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  150. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  151. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  152. data/lib/graphql/rubocop.rb +4 -0
  153. data/lib/graphql/scalar_type.rb +3 -1
  154. data/lib/graphql/schema/addition.rb +247 -0
  155. data/lib/graphql/schema/argument.rb +177 -21
  156. data/lib/graphql/schema/build_from_definition.rb +150 -55
  157. data/lib/graphql/schema/default_type_error.rb +2 -0
  158. data/lib/graphql/schema/directive/feature.rb +1 -1
  159. data/lib/graphql/schema/directive/flagged.rb +57 -0
  160. data/lib/graphql/schema/directive/include.rb +1 -1
  161. data/lib/graphql/schema/directive/skip.rb +1 -1
  162. data/lib/graphql/schema/directive/transform.rb +14 -2
  163. data/lib/graphql/schema/directive.rb +103 -4
  164. data/lib/graphql/schema/enum.rb +72 -11
  165. data/lib/graphql/schema/enum_value.rb +18 -6
  166. data/lib/graphql/schema/field/connection_extension.rb +4 -2
  167. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  168. data/lib/graphql/schema/field.rb +332 -111
  169. data/lib/graphql/schema/field_extension.rb +89 -2
  170. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  171. data/lib/graphql/schema/finder.rb +5 -5
  172. data/lib/graphql/schema/input_object.rb +79 -55
  173. data/lib/graphql/schema/interface.rb +12 -20
  174. data/lib/graphql/schema/introspection_system.rb +1 -1
  175. data/lib/graphql/schema/list.rb +21 -4
  176. data/lib/graphql/schema/loader.rb +11 -0
  177. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  178. data/lib/graphql/schema/member/base_dsl_methods.rb +5 -16
  179. data/lib/graphql/schema/member/build_type.rb +4 -7
  180. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  181. data/lib/graphql/schema/member/has_arguments.rb +166 -74
  182. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  183. data/lib/graphql/schema/member/has_directives.rb +98 -0
  184. data/lib/graphql/schema/member/has_fields.rb +77 -22
  185. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  186. data/lib/graphql/schema/member/has_validators.rb +31 -0
  187. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  188. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  189. data/lib/graphql/schema/member/validates_input.rb +2 -2
  190. data/lib/graphql/schema/member.rb +5 -0
  191. data/lib/graphql/schema/middleware_chain.rb +1 -1
  192. data/lib/graphql/schema/non_null.rb +9 -3
  193. data/lib/graphql/schema/object.rb +40 -80
  194. data/lib/graphql/schema/printer.rb +16 -20
  195. data/lib/graphql/schema/relay_classic_mutation.rb +38 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -2
  197. data/lib/graphql/schema/resolver.rb +110 -64
  198. data/lib/graphql/schema/scalar.rb +18 -2
  199. data/lib/graphql/schema/subscription.rb +55 -9
  200. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  201. data/lib/graphql/schema/traversal.rb +1 -1
  202. data/lib/graphql/schema/type_expression.rb +1 -1
  203. data/lib/graphql/schema/type_membership.rb +18 -4
  204. data/lib/graphql/schema/union.rb +8 -1
  205. data/lib/graphql/schema/validation.rb +4 -2
  206. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  207. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  208. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  209. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  210. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  211. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  212. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  213. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  214. data/lib/graphql/schema/validator.rb +171 -0
  215. data/lib/graphql/schema/warden.rb +126 -53
  216. data/lib/graphql/schema.rb +262 -281
  217. data/lib/graphql/static_validation/all_rules.rb +2 -0
  218. data/lib/graphql/static_validation/base_visitor.rb +9 -6
  219. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  220. data/lib/graphql/static_validation/error.rb +3 -1
  221. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  222. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -2
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +6 -2
  224. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  225. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  226. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  227. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -47
  229. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  230. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  231. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  232. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  233. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  234. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  235. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  236. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  237. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  238. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  239. data/lib/graphql/static_validation/validation_context.rb +12 -2
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +41 -10
  242. data/lib/graphql/static_validation.rb +1 -0
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/string_type.rb +1 -1
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +39 -8
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +0 -3
  247. data/lib/graphql/subscriptions/event.rb +68 -32
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  249. data/lib/graphql/subscriptions/serialize.rb +34 -5
  250. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  251. data/lib/graphql/subscriptions.rb +34 -39
  252. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
  253. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  254. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  255. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +24 -12
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  260. data/lib/graphql/tracing.rb +2 -2
  261. data/lib/graphql/types/big_int.rb +5 -1
  262. data/lib/graphql/types/int.rb +10 -3
  263. data/lib/graphql/types/iso_8601_date.rb +13 -5
  264. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  265. data/lib/graphql/types/relay/base_connection.rb +6 -91
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  268. data/lib/graphql/types/relay/default_relay.rb +31 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  270. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  271. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  272. data/lib/graphql/types/relay/node.rb +2 -4
  273. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  274. data/lib/graphql/types/relay/node_field.rb +3 -22
  275. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -3
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +1 -1
  281. data/lib/graphql/union_type.rb +3 -1
  282. data/lib/graphql/upgrader/member.rb +1 -0
  283. data/lib/graphql/upgrader/schema.rb +1 -0
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +68 -37
  286. data/readme.md +3 -6
  287. metadata +83 -113
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/types/relay/base_field.rb +0 -22
  290. data/lib/graphql/types/relay/base_interface.rb +0 -29
  291. data/lib/graphql/types/relay/base_object.rb +0 -26
  292. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  293. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -15,23 +15,110 @@ module GraphQL
15
15
  # @return [Object]
16
16
  attr_reader :options
17
17
 
18
+ # @return [Array<Symbol>, nil] `default_argument`s added, if any were added (otherwise, `nil`)
19
+ attr_reader :added_default_arguments
20
+
18
21
  # Called when the extension is mounted with `extension(name, options)`.
19
- # The instance is frozen to avoid improper use of state during execution.
22
+ # The instance will be frozen to avoid improper use of state during execution.
20
23
  # @param field [GraphQL::Schema::Field] The field where this extension was mounted
21
24
  # @param options [Object] The second argument to `extension`, or `{}` if nothing was passed.
22
25
  def initialize(field:, options:)
23
26
  @field = field
24
27
  @options = options || {}
28
+ @added_default_arguments = nil
25
29
  apply
26
- freeze
27
30
  end
28
31
 
32
+ class << self
33
+ # @return [Array(Array, Hash), nil] A list of default argument configs, or `nil` if there aren't any
34
+ def default_argument_configurations
35
+ args = superclass.respond_to?(:default_argument_configurations) ? superclass.default_argument_configurations : nil
36
+ if @own_default_argument_configurations
37
+ if args
38
+ args.concat(@own_default_argument_configurations)
39
+ else
40
+ args = @own_default_argument_configurations.dup
41
+ end
42
+ end
43
+ args
44
+ end
45
+
46
+ # @see Argument#initialize
47
+ # @see HasArguments#argument
48
+ def default_argument(*argument_args, **argument_kwargs)
49
+ configs = @own_default_argument_configurations ||= []
50
+ configs << [argument_args, argument_kwargs]
51
+ end
52
+
53
+ # If configured, these `extras` will be added to the field if they aren't already present,
54
+ # but removed by from `arguments` before the field's `resolve` is called.
55
+ # (The extras _will_ be present for other extensions, though.)
56
+ #
57
+ # @param new_extras [Array<Symbol>] If provided, assign extras used by this extension
58
+ # @return [Array<Symbol>] any extras assigned to this extension
59
+ def extras(new_extras = nil)
60
+ if new_extras
61
+ @own_extras = new_extras
62
+ end
63
+
64
+ inherited_extras = self.superclass.respond_to?(:extras) ? superclass.extras : nil
65
+ if @own_extras
66
+ if inherited_extras
67
+ inherited_extras + @own_extras
68
+ else
69
+ @own_extras
70
+ end
71
+ elsif inherited_extras
72
+ inherited_extras
73
+ else
74
+ NO_EXTRAS
75
+ end
76
+ end
77
+ end
78
+
79
+ NO_EXTRAS = [].freeze
80
+ private_constant :NO_EXTRAS
81
+
29
82
  # Called when this extension is attached to a field.
30
83
  # The field definition may be extended during this method.
31
84
  # @return [void]
32
85
  def apply
33
86
  end
34
87
 
88
+ # Called after the field's definition block has been executed.
89
+ # (Any arguments from the block are present on `field`)
90
+ # @return [void]
91
+ def after_define
92
+ end
93
+
94
+ # @api private
95
+ def after_define_apply
96
+ after_define
97
+ if (configs = self.class.default_argument_configurations)
98
+ existing_keywords = field.all_argument_definitions.map(&:keyword)
99
+ existing_keywords.uniq!
100
+ @added_default_arguments = []
101
+ configs.each do |config|
102
+ argument_args, argument_kwargs = config
103
+ arg_name = argument_args[0]
104
+ if !existing_keywords.include?(arg_name)
105
+ @added_default_arguments << arg_name
106
+ field.argument(*argument_args, **argument_kwargs)
107
+ end
108
+ end
109
+ end
110
+ if (extras = self.class.extras).any?
111
+ @added_extras = extras - field.extras
112
+ field.extras(@added_extras)
113
+ else
114
+ @added_extras = nil
115
+ end
116
+ freeze
117
+ end
118
+
119
+ # @api private
120
+ attr_reader :added_extras
121
+
35
122
  # Called before resolving {#field}. It should either:
36
123
  #
37
124
  # - `yield` values to continue execution; OR
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Schema
3
4
  module FindInheritedValue
@@ -20,7 +21,9 @@ module GraphQL
20
21
  if self.is_a?(Class)
21
22
  superclass.respond_to?(method_name, true) ? superclass.send(method_name) : default_value
22
23
  else
23
- ancestors[1..-1].each do |ancestor|
24
+ ancestors_except_self = ancestors
25
+ ancestors_except_self.delete(self)
26
+ ancestors_except_self.each do |ancestor|
24
27
  if ancestor.respond_to?(method_name, true)
25
28
  return ancestor.send(method_name)
26
29
  end
@@ -38,7 +38,7 @@ module GraphQL
38
38
 
39
39
  find_in_directive(directive, path: path)
40
40
  else
41
- type = schema.get_type(type_or_directive)
41
+ type = schema.get_type(type_or_directive) # rubocop:disable Development/ContextIsPassedCop -- build-time
42
42
 
43
43
  if type.nil?
44
44
  raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
@@ -56,7 +56,7 @@ module GraphQL
56
56
 
57
57
  def find_in_directive(directive, path:)
58
58
  argument_name = path.shift
59
- argument = directive.arguments[argument_name]
59
+ argument = directive.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
60
60
 
61
61
  if argument.nil?
62
62
  raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
@@ -102,7 +102,7 @@ module GraphQL
102
102
 
103
103
  def find_in_field(field, path:)
104
104
  argument_name = path.shift
105
- argument = field.arguments[argument_name]
105
+ argument = field.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
106
106
 
107
107
  if argument.nil?
108
108
  raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
@@ -119,7 +119,7 @@ module GraphQL
119
119
 
120
120
  def find_in_input_object(input_object, path:)
121
121
  field_name = path.shift
122
- input_field = input_object.arguments[field_name]
122
+ input_field = input_object.get_argument(field_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
123
123
 
124
124
  if input_field.nil?
125
125
  raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
@@ -136,7 +136,7 @@ module GraphQL
136
136
 
137
137
  def find_in_enum_type(enum_type, path:)
138
138
  value_name = path.shift
139
- enum_value = enum_type.values[value_name]
139
+ enum_value = enum_type.enum_values.find { |v| v.graphql_name == value_name } # rubocop:disable Development/ContextIsPassedCop -- build-time, not runtime
140
140
 
141
141
  if enum_value.nil?
142
142
  raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
@@ -7,9 +7,18 @@ module GraphQL
7
7
  extend GraphQL::Schema::Member::HasArguments
8
8
  extend GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader
9
9
  extend GraphQL::Schema::Member::ValidatesInput
10
+ extend GraphQL::Schema::Member::HasValidators
10
11
 
11
12
  include GraphQL::Dig
12
13
 
14
+ # @return [GraphQL::Query::Context] The context for this query
15
+ attr_reader :context
16
+ # @return [GraphQL::Query::Arguments, GraphQL::Execution::Interpereter::Arguments] The underlying arguments instance
17
+ attr_reader :arguments
18
+
19
+ # Ruby-like hash behaviors, read-only
20
+ def_delegators :@ruby_style_hash, :keys, :values, :each, :map, :any?, :empty?
21
+
13
22
  def initialize(arguments = nil, ruby_kwargs: nil, context:, defaults_used:)
14
23
  @context = context
15
24
  if ruby_kwargs
@@ -22,7 +31,7 @@ module GraphQL
22
31
  end
23
32
  # Apply prepares, not great to have it duplicated here.
24
33
  maybe_lazies = []
25
- self.class.arguments.each_value do |arg_defn|
34
+ self.class.arguments(context).each_value do |arg_defn|
26
35
  ruby_kwargs_key = arg_defn.keyword
27
36
 
28
37
  if @ruby_style_hash.key?(ruby_kwargs_key)
@@ -31,20 +40,17 @@ module GraphQL
31
40
  # With the interpreter, it's done during `coerce_arguments`
32
41
  if loads && !arg_defn.from_resolver? && !context.interpreter?
33
42
  value = @ruby_style_hash[ruby_kwargs_key]
34
- loaded_value = if arg_defn.type.list?
35
- value.map { |val| load_application_object(arg_defn, loads, val, context) }
36
- else
37
- load_application_object(arg_defn, loads, value, context)
38
- end
43
+ loaded_value = arg_defn.load_and_authorize_value(self, value, context)
39
44
  maybe_lazies << context.schema.after_lazy(loaded_value) do |loaded_value|
40
- @ruby_style_hash[ruby_kwargs_key] = loaded_value
45
+ overwrite_argument(ruby_kwargs_key, loaded_value)
41
46
  end
42
47
  end
43
48
 
44
49
  # Weirdly, procs are applied during coercion, but not methods.
45
50
  # Probably because these methods require a `self`.
46
51
  if arg_defn.prepare.is_a?(Symbol) || context.nil? || !context.interpreter?
47
- @ruby_style_hash[ruby_kwargs_key] = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
52
+ prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
53
+ overwrite_argument(ruby_kwargs_key, prepared_value)
48
54
  end
49
55
  end
50
56
  end
@@ -52,19 +58,8 @@ module GraphQL
52
58
  @maybe_lazies = maybe_lazies
53
59
  end
54
60
 
55
- # @return [GraphQL::Query::Context] The context for this query
56
- attr_reader :context
57
-
58
- # @return [GraphQL::Query::Arguments, GraphQL::Execution::Interpereter::Arguments] The underlying arguments instance
59
- attr_reader :arguments
60
-
61
- # Ruby-like hash behaviors, read-only
62
- def_delegators :@ruby_style_hash, :keys, :values, :each, :map, :any?, :empty?
63
-
64
61
  def to_h
65
- @ruby_style_hash.inject({}) do |h, (key, value)|
66
- h.merge(key => unwrap_value(value))
67
- end
62
+ unwrap_value(@ruby_style_hash)
68
63
  end
69
64
 
70
65
  def to_hash
@@ -72,8 +67,11 @@ module GraphQL
72
67
  end
73
68
 
74
69
  def prepare
75
- if context
76
- context.schema.after_any_lazies(@maybe_lazies) do
70
+ if @context
71
+ @context.schema.after_any_lazies(@maybe_lazies) do
72
+ object = @context[:current_object]
73
+ # Pass this object's class with `as` so that messages are rendered correctly from inherited validators
74
+ Schema::Validator.validate!(self.class.validators, object, @context, @ruby_style_hash, as: self.class)
77
75
  self
78
76
  end
79
77
  else
@@ -81,13 +79,28 @@ module GraphQL
81
79
  end
82
80
  end
83
81
 
82
+ def self.authorized?(obj, value, ctx)
83
+ # Authorize each argument (but this doesn't apply if `prepare` is implemented):
84
+ if value.respond_to?(:key?)
85
+ arguments(ctx).each do |_name, input_obj_arg|
86
+ input_obj_arg = input_obj_arg.type_class
87
+ if value.key?(input_obj_arg.keyword) &&
88
+ !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
89
+ return false
90
+ end
91
+ end
92
+ end
93
+ # It didn't early-return false:
94
+ true
95
+ end
96
+
84
97
  def unwrap_value(value)
85
98
  case value
86
99
  when Array
87
100
  value.map { |item| unwrap_value(item) }
88
101
  when Hash
89
- value.inject({}) do |h, (key, value)|
90
- h.merge(key => unwrap_value(value))
102
+ value.reduce({}) do |h, (key, value)|
103
+ h.merge!(key => unwrap_value(value))
91
104
  end
92
105
  when InputObject
93
106
  value.to_h
@@ -131,8 +144,11 @@ module GraphQL
131
144
  self[#{method_name.inspect}]
132
145
  end
133
146
  RUBY
147
+ argument_defn
134
148
  end
135
149
 
150
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
151
+
136
152
  def to_graphql
137
153
  type_defn = GraphQL::InputObjectType.new
138
154
  type_defn.name = graphql_name
@@ -140,8 +156,8 @@ module GraphQL
140
156
  type_defn.metadata[:type_class] = self
141
157
  type_defn.mutation = mutation
142
158
  type_defn.ast_node = ast_node
143
- arguments.each do |name, arg|
144
- type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
159
+ all_argument_definitions.each do |arg|
160
+ type_defn.arguments[arg.graphql_definition(silence_deprecation_warning: true).name] = arg.graphql_definition(silence_deprecation_warning: true) # rubocop:disable Development/ContextIsPassedCop -- legacy-related
145
161
  end
146
162
  # Make a reference to a classic-style Arguments class
147
163
  self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
@@ -157,10 +173,8 @@ module GraphQL
157
173
  # @api private
158
174
  INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
159
175
 
160
-
161
- def validate_non_null_input(input, ctx)
176
+ def validate_non_null_input(input, ctx, max_errors: nil)
162
177
  result = GraphQL::Query::InputValidationResult.new
163
-
164
178
  warden = ctx.warden
165
179
 
166
180
  if input.is_a?(Array)
@@ -168,21 +182,14 @@ module GraphQL
168
182
  return result
169
183
  end
170
184
 
171
- input = begin
172
- input.to_h
173
- rescue
174
- begin
175
- # Handle ActionController::Parameters:
176
- input.to_unsafe_h
177
- rescue
178
- # We're not sure it'll act like a hash, so reject it:
179
- result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
180
- return result
181
- end
185
+ if !(input.respond_to?(:to_h) || input.respond_to?(:to_unsafe_h))
186
+ # We're not sure it'll act like a hash, so reject it:
187
+ result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
188
+ return result
182
189
  end
183
190
 
184
191
  # Inject missing required arguments
185
- missing_required_inputs = self.arguments.reduce({}) do |m, (argument_name, argument)|
192
+ missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
186
193
  if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
187
194
  m[argument_name] = nil
188
195
  end
@@ -190,16 +197,19 @@ module GraphQL
190
197
  m
191
198
  end
192
199
 
193
- input.merge(missing_required_inputs).each do |argument_name, value|
194
- argument = warden.get_argument(self, argument_name)
195
- # Items in the input that are unexpected
196
- unless argument
197
- result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
198
- next
200
+
201
+ [input, missing_required_inputs].each do |args_to_validate|
202
+ args_to_validate.each do |argument_name, value|
203
+ argument = warden.get_argument(self, argument_name)
204
+ # Items in the input that are unexpected
205
+ unless argument
206
+ result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
207
+ next
208
+ end
209
+ # Items in the input that are expected, but have invalid values
210
+ argument_result = argument.type.validate_input(value, ctx)
211
+ result.merge_result!(argument_name, argument_result) unless argument_result.valid?
199
212
  end
200
- # Items in the input that are expected, but have invalid values
201
- argument_result = argument.type.validate_input(value, ctx)
202
- result.merge_result!(argument_name, argument_result) unless argument_result.valid?
203
213
  end
204
214
 
205
215
  result
@@ -213,20 +223,24 @@ module GraphQL
213
223
  arguments = coerce_arguments(nil, value, ctx)
214
224
 
215
225
  ctx.schema.after_lazy(arguments) do |resolved_arguments|
216
- input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
217
- input_obj_instance.prepare
226
+ if resolved_arguments.is_a?(GraphQL::Error)
227
+ raise resolved_arguments
228
+ else
229
+ input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
230
+ input_obj_instance.prepare
231
+ end
218
232
  end
219
233
  end
220
234
 
221
235
  # It's funny to think of a _result_ of an input object.
222
236
  # This is used for rendering the default value in introspection responses.
223
237
  def coerce_result(value, ctx)
224
- # Allow the application to provide values as :symbols, and convert them to the strings
225
- value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
238
+ # Allow the application to provide values as :snake_symbols, and convert them to the camelStrings
239
+ value = value.reduce({}) { |memo, (k, v)| memo[Member::BuildType.camelize(k.to_s)] = v; memo }
226
240
 
227
241
  result = {}
228
242
 
229
- arguments.each do |input_key, input_field_defn|
243
+ arguments(ctx).each do |input_key, input_field_defn|
230
244
  input_value = value[input_key]
231
245
  if value.key?(input_key)
232
246
  result[input_key] = if input_value.nil?
@@ -240,6 +254,16 @@ module GraphQL
240
254
  result
241
255
  end
242
256
  end
257
+
258
+ private
259
+
260
+ def overwrite_argument(key, value)
261
+ # Argument keywords come in frozen from the interpreter, dup them before modifying them.
262
+ if @ruby_style_hash.frozen?
263
+ @ruby_style_hash = @ruby_style_hash.dup
264
+ end
265
+ @ruby_style_hash[key] = value
266
+ end
243
267
  end
244
268
  end
245
269
  end
@@ -15,6 +15,8 @@ module GraphQL
15
15
  include GraphQL::Schema::Member::Scoped
16
16
  include GraphQL::Schema::Member::HasAstNode
17
17
  include GraphQL::Schema::Member::HasUnresolvedTypeError
18
+ include GraphQL::Schema::Member::HasDirectives
19
+ include GraphQL::Schema::Member::HasInterfaces
18
20
 
19
21
  # Methods defined in this block will be:
20
22
  # - Added as class methods to this interface
@@ -56,9 +58,10 @@ module GraphQL
56
58
  child_class.extend(Schema::Interface::DefinitionMethods)
57
59
 
58
60
  child_class.type_membership_class(self.type_membership_class)
59
- child_class.own_interfaces << self
60
- child_class.interfaces.reverse_each do |interface_defn|
61
- child_class.extend(interface_defn::DefinitionMethods)
61
+ child_class.ancestors.reverse_each do |ancestor|
62
+ if ancestor.const_defined?(:DefinitionMethods)
63
+ child_class.extend(ancestor::DefinitionMethods)
64
+ end
62
65
  end
63
66
 
64
67
  # Use an instance variable to tell whether it's been included previously or not;
@@ -72,16 +75,13 @@ module GraphQL
72
75
  end
73
76
  child_class.introspection(introspection)
74
77
  child_class.description(description)
75
- if overridden_graphql_name
76
- child_class.graphql_name(overridden_graphql_name)
77
- end
78
78
  # If interfaces are mixed into each other, only define this class once
79
79
  if !child_class.const_defined?(:UnresolvedTypeError, false)
80
80
  add_unresolved_type_error(child_class)
81
81
  end
82
82
  elsif child_class < GraphQL::Schema::Object
83
83
  # This is being included into an object type, make sure it's using `implements(...)`
84
- backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
84
+ backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
85
85
  if !backtrace_line
86
86
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
87
87
  end
@@ -100,6 +100,8 @@ module GraphQL
100
100
  end
101
101
  end
102
102
 
103
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
104
+
103
105
  def to_graphql
104
106
  type_defn = GraphQL::InterfaceType.new
105
107
  type_defn.name = graphql_name
@@ -107,9 +109,9 @@ module GraphQL
107
109
  type_defn.orphan_types = orphan_types
108
110
  type_defn.type_membership_class = self.type_membership_class
109
111
  type_defn.ast_node = ast_node
110
- fields.each do |field_name, field_inst|
111
- field_defn = field_inst.graphql_definition
112
- type_defn.fields[field_defn.name] = field_defn
112
+ fields.each do |field_name, field_inst| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
113
+ field_defn = field_inst.graphql_definition(silence_deprecation_warning: true)
114
+ type_defn.fields[field_defn.name] = field_defn # rubocop:disable Development/ContextIsPassedCop -- legacy-related
113
115
  end
114
116
  type_defn.metadata[:type_class] = self
115
117
  if respond_to?(:resolve_type)
@@ -121,16 +123,6 @@ module GraphQL
121
123
  def kind
122
124
  GraphQL::TypeKinds::INTERFACE
123
125
  end
124
-
125
- protected
126
-
127
- def own_interfaces
128
- @own_interfaces ||= []
129
- end
130
-
131
- def interfaces
132
- own_interfaces + (own_interfaces.map { |i| i.own_interfaces }).flatten
133
- end
134
126
  end
135
127
 
136
128
  # Extend this _after_ `DefinitionMethods` is defined, so it will be used
@@ -107,7 +107,7 @@ module GraphQL
107
107
  dup_type_class(const)
108
108
  else
109
109
  # Use `.to_graphql` to get a freshly-made version, not shared between schemas
110
- const.to_graphql
110
+ const.deprecated_to_graphql
111
111
  end
112
112
  rescue NameError
113
113
  # Dup the built-in so that the cached fields aren't shared
@@ -8,8 +8,10 @@ module GraphQL
8
8
  class List < GraphQL::Schema::Wrapper
9
9
  include Schema::Member::ValidatesInput
10
10
 
11
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
12
+
11
13
  def to_graphql
12
- @of_type.graphql_definition.to_list_type
14
+ @of_type.graphql_definition(silence_deprecation_warning: true).to_list_type
13
15
  end
14
16
 
15
17
  # @return [GraphQL::TypeKinds::LIST]
@@ -49,15 +51,24 @@ module GraphQL
49
51
  end
50
52
  end
51
53
 
52
- def validate_non_null_input(value, ctx)
54
+ def validate_non_null_input(value, ctx, max_errors: nil)
53
55
  result = GraphQL::Query::InputValidationResult.new
54
56
  ensure_array(value).each_with_index do |item, index|
55
57
  item_result = of_type.validate_input(item, ctx)
56
- if !item_result.valid?
58
+ unless item_result.valid?
59
+ if max_errors
60
+ if max_errors == 0
61
+ add_max_errros_reached_message(result)
62
+ break
63
+ end
64
+
65
+ max_errors -= 1
66
+ end
67
+
57
68
  result.merge_result!(index, item_result)
58
69
  end
59
70
  end
60
- result
71
+ result.valid? ? nil : result
61
72
  end
62
73
 
63
74
  private
@@ -70,6 +81,12 @@ module GraphQL
70
81
  [value]
71
82
  end
72
83
  end
84
+
85
+ def add_max_errros_reached_message(result)
86
+ message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
87
+ item_result = GraphQL::Query::InputValidationResult.from_problem(message)
88
+ result.merge_result!(nil, item_result)
89
+ end
73
90
  end
74
91
  end
75
92
  end
@@ -34,6 +34,7 @@ module GraphQL
34
34
  Class.new(GraphQL::Schema) do
35
35
  orphan_types(types.values)
36
36
  directives(directives)
37
+ description(schema["description"])
37
38
 
38
39
  def self.resolve_type(*)
39
40
  raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
@@ -141,6 +142,7 @@ module GraphQL
141
142
  Class.new(GraphQL::Schema::Scalar) do
142
143
  graphql_name(type["name"])
143
144
  description(type["description"])
145
+ specified_by_url(type["specifiedByUrl"])
144
146
  end
145
147
  end
146
148
  when "UNION"
@@ -160,6 +162,7 @@ module GraphQL
160
162
  graphql_name(directive["name"])
161
163
  description(directive["description"])
162
164
  locations(*directive["locations"].map(&:to_sym))
165
+ repeatable(directive["isRepeatable"])
163
166
  loader.build_arguments(self, directive["args"], type_resolver)
164
167
  end
165
168
  end
@@ -169,6 +172,12 @@ module GraphQL
169
172
  def build_fields(type_defn, fields, type_resolver)
170
173
  loader = self
171
174
  fields.each do |field_hash|
175
+ unwrapped_field_hash = field_hash
176
+ while (of_type = unwrapped_field_hash["ofType"])
177
+ unwrapped_field_hash = of_type
178
+ end
179
+ type_name = unwrapped_field_hash["name"]
180
+
172
181
  type_defn.field(
173
182
  field_hash["name"],
174
183
  type: type_resolver.call(field_hash["type"]),
@@ -176,6 +185,8 @@ module GraphQL
176
185
  deprecation_reason: field_hash["deprecationReason"],
177
186
  null: true,
178
187
  camelize: false,
188
+ connection_extension: nil,
189
+ connection: type_name.end_with?("Connection"),
179
190
  ) do
180
191
  if field_hash["args"].any?
181
192
  loader.build_arguments(self, field_hash["args"], type_resolver)
@@ -85,8 +85,15 @@ module GraphQL
85
85
  define_method(name) do |*args|
86
86
  if args.any?
87
87
  instance_variable_set(ivar_name, args)
88
+ else
89
+ if (v = instance_variable_get(ivar_name))
90
+ v
91
+ elsif (ancestor = ancestors.find { |i| i.respond_to?(name) && i != self })
92
+ ancestor.public_send(name)
93
+ else
94
+ nil
95
+ end
88
96
  end
89
- instance_variable_get(ivar_name) || ((int = interfaces.first { |i| i.respond_to?()}) && int.public_send(name))
90
97
  end
91
98
  end
92
99
  end
@@ -116,8 +123,13 @@ module GraphQL
116
123
  end
117
124
 
118
125
  module ToGraphQLExtension
119
- def to_graphql
120
- defn = super
126
+ def to_graphql(*args, **kwargs)
127
+
128
+ defn = if args.empty? && kwargs.empty?
129
+ super()
130
+ else
131
+ super
132
+ end
121
133
  accepts_definition_methods.each do |method_name|
122
134
  value = public_send(method_name)
123
135
  if !value.nil?