graphql 1.10.1 → 1.13.0

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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +18 -2
  3. data/lib/generators/graphql/install_generator.rb +36 -6
  4. data/lib/generators/graphql/loader_generator.rb +1 -0
  5. data/lib/generators/graphql/mutation_generator.rb +2 -1
  6. data/lib/generators/graphql/object_generator.rb +54 -9
  7. data/lib/generators/graphql/relay.rb +63 -0
  8. data/lib/generators/graphql/relay_generator.rb +21 -0
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  17. data/lib/generators/graphql/templates/base_object.erb +2 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/enum.erb +2 -0
  21. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  22. data/lib/generators/graphql/templates/interface.erb +2 -0
  23. data/lib/generators/graphql/templates/loader.erb +2 -0
  24. data/lib/generators/graphql/templates/mutation.erb +2 -0
  25. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  26. data/lib/generators/graphql/templates/node_type.erb +9 -0
  27. data/lib/generators/graphql/templates/object.erb +3 -1
  28. data/lib/generators/graphql/templates/query_type.erb +3 -3
  29. data/lib/generators/graphql/templates/scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/schema.erb +21 -33
  31. data/lib/generators/graphql/templates/union.erb +3 -1
  32. data/lib/generators/graphql/type_generator.rb +1 -1
  33. data/lib/graphql/analysis/analyze_query.rb +7 -0
  34. data/lib/graphql/analysis/ast/field_usage.rb +24 -1
  35. data/lib/graphql/analysis/ast/query_complexity.rb +126 -109
  36. data/lib/graphql/analysis/ast/visitor.rb +13 -5
  37. data/lib/graphql/analysis/ast.rb +11 -2
  38. data/lib/graphql/argument.rb +3 -3
  39. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  40. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  41. data/lib/graphql/backtrace/table.rb +34 -3
  42. data/lib/graphql/backtrace/traced_error.rb +0 -1
  43. data/lib/graphql/backtrace/tracer.rb +40 -9
  44. data/lib/graphql/backtrace.rb +28 -19
  45. data/lib/graphql/backwards_compatibility.rb +2 -1
  46. data/lib/graphql/base_type.rb +1 -1
  47. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  48. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  49. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  50. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  51. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  52. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  53. data/lib/graphql/dataloader/request.rb +19 -0
  54. data/lib/graphql/dataloader/request_all.rb +19 -0
  55. data/lib/graphql/dataloader/source.rb +155 -0
  56. data/lib/graphql/dataloader.rb +308 -0
  57. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  58. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  59. data/lib/graphql/define/instance_definable.rb +34 -4
  60. data/lib/graphql/define/type_definer.rb +5 -5
  61. data/lib/graphql/deprecated_dsl.rb +18 -5
  62. data/lib/graphql/deprecation.rb +9 -0
  63. data/lib/graphql/directive.rb +4 -4
  64. data/lib/graphql/enum_type.rb +7 -1
  65. data/lib/graphql/execution/errors.rb +110 -7
  66. data/lib/graphql/execution/execute.rb +8 -1
  67. data/lib/graphql/execution/instrumentation.rb +1 -1
  68. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  69. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
  71. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  72. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  73. data/lib/graphql/execution/interpreter/runtime.rb +685 -421
  74. data/lib/graphql/execution/interpreter.rb +42 -13
  75. data/lib/graphql/execution/lazy.rb +5 -1
  76. data/lib/graphql/execution/lookahead.rb +25 -110
  77. data/lib/graphql/execution/multiplex.rb +37 -25
  78. data/lib/graphql/field.rb +5 -1
  79. data/lib/graphql/function.rb +4 -0
  80. data/lib/graphql/input_object_type.rb +6 -0
  81. data/lib/graphql/integer_decoding_error.rb +17 -0
  82. data/lib/graphql/integer_encoding_error.rb +18 -2
  83. data/lib/graphql/interface_type.rb +7 -0
  84. data/lib/graphql/internal_representation/document.rb +2 -2
  85. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  86. data/lib/graphql/internal_representation/scope.rb +2 -2
  87. data/lib/graphql/internal_representation/visit.rb +2 -2
  88. data/lib/graphql/introspection/directive_type.rb +8 -4
  89. data/lib/graphql/introspection/entry_points.rb +2 -2
  90. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  91. data/lib/graphql/introspection/field_type.rb +9 -5
  92. data/lib/graphql/introspection/input_value_type.rb +15 -3
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +4 -4
  95. data/lib/graphql/introspection/type_type.rb +16 -12
  96. data/lib/graphql/introspection.rb +96 -0
  97. data/lib/graphql/invalid_null_error.rb +18 -0
  98. data/lib/graphql/language/block_string.rb +20 -5
  99. data/lib/graphql/language/cache.rb +37 -0
  100. data/lib/graphql/language/document_from_schema_definition.rb +73 -25
  101. data/lib/graphql/language/lexer.rb +4 -3
  102. data/lib/graphql/language/lexer.rl +3 -3
  103. data/lib/graphql/language/nodes.rb +51 -89
  104. data/lib/graphql/language/parser.rb +552 -530
  105. data/lib/graphql/language/parser.y +114 -99
  106. data/lib/graphql/language/printer.rb +7 -2
  107. data/lib/graphql/language/sanitized_printer.rb +222 -0
  108. data/lib/graphql/language/token.rb +0 -4
  109. data/lib/graphql/language/visitor.rb +2 -2
  110. data/lib/graphql/language.rb +2 -0
  111. data/lib/graphql/name_validator.rb +2 -7
  112. data/lib/graphql/object_type.rb +44 -35
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +14 -1
  114. data/lib/graphql/pagination/array_connection.rb +2 -2
  115. data/lib/graphql/pagination/connection.rb +75 -20
  116. data/lib/graphql/pagination/connections.rb +83 -31
  117. data/lib/graphql/pagination/relation_connection.rb +34 -14
  118. data/lib/graphql/parse_error.rb +0 -1
  119. data/lib/graphql/query/arguments.rb +4 -3
  120. data/lib/graphql/query/arguments_cache.rb +1 -2
  121. data/lib/graphql/query/context.rb +42 -7
  122. data/lib/graphql/query/executor.rb +0 -1
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +23 -6
  125. data/lib/graphql/query/literal_input.rb +1 -1
  126. data/lib/graphql/query/null_context.rb +24 -8
  127. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  128. data/lib/graphql/query/serial_execution.rb +1 -0
  129. data/lib/graphql/query/validation_pipeline.rb +5 -2
  130. data/lib/graphql/query/variable_validation_error.rb +1 -1
  131. data/lib/graphql/query/variables.rb +14 -4
  132. data/lib/graphql/query.rb +68 -13
  133. data/lib/graphql/railtie.rb +9 -1
  134. data/lib/graphql/rake_task.rb +12 -9
  135. data/lib/graphql/relay/array_connection.rb +10 -12
  136. data/lib/graphql/relay/base_connection.rb +26 -13
  137. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  138. data/lib/graphql/relay/connection_type.rb +1 -1
  139. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  140. data/lib/graphql/relay/mutation.rb +1 -0
  141. data/lib/graphql/relay/node.rb +3 -0
  142. data/lib/graphql/relay/range_add.rb +23 -9
  143. data/lib/graphql/relay/relation_connection.rb +8 -10
  144. data/lib/graphql/relay/type_extensions.rb +2 -0
  145. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  146. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  147. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  148. data/lib/graphql/rubocop.rb +4 -0
  149. data/lib/graphql/scalar_type.rb +16 -1
  150. data/lib/graphql/schema/addition.rb +247 -0
  151. data/lib/graphql/schema/argument.rb +210 -12
  152. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  153. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  154. data/lib/graphql/schema/build_from_definition.rb +213 -86
  155. data/lib/graphql/schema/default_type_error.rb +2 -0
  156. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  157. data/lib/graphql/schema/directive/feature.rb +1 -1
  158. data/lib/graphql/schema/directive/flagged.rb +57 -0
  159. data/lib/graphql/schema/directive/include.rb +1 -1
  160. data/lib/graphql/schema/directive/skip.rb +1 -1
  161. data/lib/graphql/schema/directive/transform.rb +14 -2
  162. data/lib/graphql/schema/directive.rb +78 -2
  163. data/lib/graphql/schema/enum.rb +80 -9
  164. data/lib/graphql/schema/enum_value.rb +17 -6
  165. data/lib/graphql/schema/field/connection_extension.rb +46 -30
  166. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  167. data/lib/graphql/schema/field.rb +285 -133
  168. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  169. data/lib/graphql/schema/finder.rb +5 -5
  170. data/lib/graphql/schema/input_object.rb +97 -89
  171. data/lib/graphql/schema/interface.rb +24 -19
  172. data/lib/graphql/schema/late_bound_type.rb +2 -2
  173. data/lib/graphql/schema/list.rb +7 -1
  174. data/lib/graphql/schema/loader.rb +137 -103
  175. data/lib/graphql/schema/member/accepts_definition.rb +8 -1
  176. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  177. data/lib/graphql/schema/member/build_type.rb +14 -7
  178. data/lib/graphql/schema/member/has_arguments.rb +205 -12
  179. data/lib/graphql/schema/member/has_ast_node.rb +4 -1
  180. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  181. data/lib/graphql/schema/member/has_directives.rb +98 -0
  182. data/lib/graphql/schema/member/has_fields.rb +95 -30
  183. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  184. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  185. data/lib/graphql/schema/member/has_validators.rb +31 -0
  186. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  187. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  188. data/lib/graphql/schema/member.rb +6 -0
  189. data/lib/graphql/schema/middleware_chain.rb +1 -1
  190. data/lib/graphql/schema/mutation.rb +4 -0
  191. data/lib/graphql/schema/non_null.rb +5 -0
  192. data/lib/graphql/schema/object.rb +47 -46
  193. data/lib/graphql/schema/possible_types.rb +9 -4
  194. data/lib/graphql/schema/printer.rb +16 -34
  195. data/lib/graphql/schema/relay_classic_mutation.rb +32 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  197. data/lib/graphql/schema/resolver.rb +123 -63
  198. data/lib/graphql/schema/scalar.rb +11 -1
  199. data/lib/graphql/schema/subscription.rb +57 -21
  200. data/lib/graphql/schema/timeout.rb +29 -15
  201. data/lib/graphql/schema/timeout_middleware.rb +3 -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 +41 -1
  205. data/lib/graphql/schema/unique_within_type.rb +1 -2
  206. data/lib/graphql/schema/validation.rb +12 -2
  207. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  208. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  209. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  210. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  211. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  212. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  213. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  214. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  215. data/lib/graphql/schema/validator.rb +174 -0
  216. data/lib/graphql/schema/warden.rb +153 -28
  217. data/lib/graphql/schema.rb +364 -330
  218. data/lib/graphql/static_validation/all_rules.rb +1 -0
  219. data/lib/graphql/static_validation/base_visitor.rb +8 -5
  220. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  221. data/lib/graphql/static_validation/error.rb +3 -1
  222. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
  224. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  225. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
  226. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  227. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -43
  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/required_arguments_are_present.rb +1 -1
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
  235. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
  236. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -8
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  238. data/lib/graphql/static_validation/validation_context.rb +9 -3
  239. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  240. data/lib/graphql/static_validation/validator.rb +42 -8
  241. data/lib/graphql/static_validation.rb +1 -0
  242. data/lib/graphql/string_encoding_error.rb +13 -3
  243. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +118 -19
  244. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  245. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  246. data/lib/graphql/subscriptions/event.rb +81 -30
  247. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  248. data/lib/graphql/subscriptions/serialize.rb +33 -6
  249. data/lib/graphql/subscriptions/subscription_root.rb +15 -4
  250. data/lib/graphql/subscriptions.rb +88 -45
  251. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  252. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  253. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  254. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  255. data/lib/graphql/tracing/platform_tracing.rb +43 -17
  256. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  257. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  258. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  259. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  260. data/lib/graphql/tracing.rb +9 -33
  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 +3 -3
  264. data/lib/graphql/types/iso_8601_date_time.rb +25 -10
  265. data/lib/graphql/types/relay/base_connection.rb +6 -90
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
  268. data/lib/graphql/types/relay/default_relay.rb +27 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +53 -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 +2 -20
  275. data/lib/graphql/types/relay/nodes_field.rb +2 -20
  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 +2 -2
  281. data/lib/graphql/union_type.rb +2 -0
  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 +65 -31
  286. data/readme.md +3 -6
  287. metadata +77 -112
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/literal_validation_error.rb +0 -6
  290. data/lib/graphql/types/relay/base_field.rb +0 -22
  291. data/lib/graphql/types/relay/base_interface.rb +0 -29
  292. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -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}`."
@@ -5,54 +5,61 @@ module GraphQL
5
5
  extend GraphQL::Schema::Member::AcceptsDefinition
6
6
  extend Forwardable
7
7
  extend GraphQL::Schema::Member::HasArguments
8
+ extend GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader
8
9
  extend GraphQL::Schema::Member::ValidatesInput
10
+ extend GraphQL::Schema::Member::HasValidators
9
11
 
10
12
  include GraphQL::Dig
11
13
 
12
- def initialize(values = nil, ruby_kwargs: nil, context:, defaults_used:)
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
+
22
+ def initialize(arguments = nil, ruby_kwargs: nil, context:, defaults_used:)
13
23
  @context = context
14
24
  if ruby_kwargs
15
25
  @ruby_style_hash = ruby_kwargs
26
+ @arguments = arguments
16
27
  else
17
- @arguments = self.class.arguments_class.new(values, context: context, defaults_used: defaults_used)
28
+ @arguments = self.class.arguments_class.new(arguments, context: context, defaults_used: defaults_used)
18
29
  # Symbolized, underscored hash:
19
30
  @ruby_style_hash = @arguments.to_kwargs
20
31
  end
21
32
  # Apply prepares, not great to have it duplicated here.
22
- @arguments_by_keyword = {}
23
- self.class.arguments.each do |name, arg_defn|
24
- @arguments_by_keyword[arg_defn.keyword] = arg_defn
33
+ maybe_lazies = []
34
+ self.class.arguments(context).each_value do |arg_defn|
25
35
  ruby_kwargs_key = arg_defn.keyword
26
- loads = arg_defn.loads
27
36
 
28
- if @ruby_style_hash.key?(ruby_kwargs_key) && loads && !arg_defn.from_resolver?
29
- value = @ruby_style_hash[ruby_kwargs_key]
30
- @ruby_style_hash[ruby_kwargs_key] = if arg_defn.type.list?
31
- value.map { |val| load_application_object(arg_defn, loads, val) }
32
- else
33
- load_application_object(arg_defn, loads, value)
37
+ if @ruby_style_hash.key?(ruby_kwargs_key)
38
+ loads = arg_defn.loads
39
+ # Resolvers do this loading themselves;
40
+ # With the interpreter, it's done during `coerce_arguments`
41
+ if loads && !arg_defn.from_resolver? && !context.interpreter?
42
+ value = @ruby_style_hash[ruby_kwargs_key]
43
+ loaded_value = arg_defn.load_and_authorize_value(self, value, context)
44
+ maybe_lazies << context.schema.after_lazy(loaded_value) do |loaded_value|
45
+ overwrite_argument(ruby_kwargs_key, loaded_value)
46
+ end
34
47
  end
35
- end
36
48
 
37
- if @ruby_style_hash.key?(ruby_kwargs_key) && arg_defn.prepare
38
- @ruby_style_hash[ruby_kwargs_key] = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
49
+ # Weirdly, procs are applied during coercion, but not methods.
50
+ # Probably because these methods require a `self`.
51
+ if arg_defn.prepare.is_a?(Symbol) || context.nil? || !context.interpreter?
52
+ prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
53
+ overwrite_argument(ruby_kwargs_key, prepared_value)
54
+ end
39
55
  end
40
56
  end
41
- end
42
-
43
- # @return [GraphQL::Query::Context] The context for this query
44
- attr_reader :context
45
-
46
- # @return [GraphQL::Query::Arguments] The underlying arguments instance
47
- attr_reader :arguments
48
57
 
49
- # Ruby-like hash behaviors, read-only
50
- def_delegators :@ruby_style_hash, :keys, :values, :each, :map, :any?, :empty?
58
+ @maybe_lazies = maybe_lazies
59
+ end
51
60
 
52
61
  def to_h
53
- @ruby_style_hash.inject({}) do |h, (key, value)|
54
- h.merge(key => unwrap_value(value))
55
- end
62
+ unwrap_value(@ruby_style_hash)
56
63
  end
57
64
 
58
65
  def to_hash
@@ -60,7 +67,16 @@ module GraphQL
60
67
  end
61
68
 
62
69
  def prepare
63
- self
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)
75
+ self
76
+ end
77
+ else
78
+ self
79
+ end
64
80
  end
65
81
 
66
82
  def unwrap_value(value)
@@ -68,8 +84,8 @@ module GraphQL
68
84
  when Array
69
85
  value.map { |item| unwrap_value(item) }
70
86
  when Hash
71
- value.inject({}) do |h, (key, value)|
72
- h.merge(key => unwrap_value(value))
87
+ value.reduce({}) do |h, (key, value)|
88
+ h.merge!(key => unwrap_value(value))
73
89
  end
74
90
  when InputObject
75
91
  value.to_h
@@ -108,9 +124,12 @@ module GraphQL
108
124
  argument_defn = super(*args, **kwargs, &block)
109
125
  # Add a method access
110
126
  method_name = argument_defn.keyword
111
- define_method(method_name) do
112
- self[method_name]
113
- end
127
+ class_eval <<-RUBY, __FILE__, __LINE__
128
+ def #{method_name}
129
+ self[#{method_name.inspect}]
130
+ end
131
+ RUBY
132
+ argument_defn
114
133
  end
115
134
 
116
135
  def to_graphql
@@ -120,8 +139,8 @@ module GraphQL
120
139
  type_defn.metadata[:type_class] = self
121
140
  type_defn.mutation = mutation
122
141
  type_defn.ast_node = ast_node
123
- arguments.each do |name, arg|
124
- type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
142
+ all_argument_definitions.each do |arg|
143
+ type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition # rubocop:disable Development/ContextIsPassedCop -- legacy-related
125
144
  end
126
145
  # Make a reference to a classic-style Arguments class
127
146
  self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
@@ -137,7 +156,6 @@ module GraphQL
137
156
  # @api private
138
157
  INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
139
158
 
140
-
141
159
  def validate_non_null_input(input, ctx)
142
160
  result = GraphQL::Query::InputValidationResult.new
143
161
 
@@ -148,36 +166,33 @@ module GraphQL
148
166
  return result
149
167
  end
150
168
 
151
- # We're not actually _using_ the coerced result, we're just
152
- # using these methods to make sure that the object will
153
- # behave like a hash below, when we call `each` on it.
154
- begin
155
- input.to_h
156
- rescue
157
- begin
158
- # Handle ActionController::Parameters:
159
- input.to_unsafe_h
160
- rescue
161
- # We're not sure it'll act like a hash, so reject it:
162
- result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
163
- return result
164
- end
169
+ if !(input.respond_to?(:to_h) || input.respond_to?(:to_unsafe_h))
170
+ # We're not sure it'll act like a hash, so reject it:
171
+ result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
172
+ return result
165
173
  end
166
174
 
167
- visible_arguments_map = warden.arguments(self).reduce({}) { |m, f| m[f.name] = f; m}
168
-
169
- # Items in the input that are unexpected
170
- input.each do |name, value|
171
- if visible_arguments_map[name].nil?
172
- result.add_problem("Argument is not defined on #{self.graphql_name}", [name])
175
+ # Inject missing required arguments
176
+ missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
177
+ if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
178
+ m[argument_name] = nil
173
179
  end
180
+
181
+ m
174
182
  end
175
183
 
176
- # Items in the input that are expected, but have invalid values
177
- visible_arguments_map.map do |name, argument|
178
- argument_result = argument.type.validate_input(input[name], ctx)
179
- if !argument_result.valid?
180
- result.merge_result!(name, argument_result)
184
+
185
+ [input, missing_required_inputs].each do |args_to_validate|
186
+ args_to_validate.each do |argument_name, value|
187
+ argument = warden.get_argument(self, argument_name)
188
+ # Items in the input that are unexpected
189
+ unless argument
190
+ result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
191
+ next
192
+ end
193
+ # Items in the input that are expected, but have invalid values
194
+ argument_result = argument.type.validate_input(value, ctx)
195
+ result.merge_result!(argument_name, argument_result) unless argument_result.valid?
181
196
  end
182
197
  end
183
198
 
@@ -188,45 +203,28 @@ module GraphQL
188
203
  if value.nil?
189
204
  return nil
190
205
  end
191
- input_values = {}
192
-
193
- arguments.each do |name, argument_defn|
194
- arg_key = argument_defn.keyword
195
- has_value = false
196
-
197
- # Accept either string or symbol
198
- field_value = if value.key?(name)
199
- has_value = true
200
- value[name]
201
- elsif value.key?(arg_key)
202
- has_value = true
203
- value[arg_key]
204
- elsif argument_defn.default_value?
205
- has_value = true
206
- argument_defn.default_value
206
+
207
+ arguments = coerce_arguments(nil, value, ctx)
208
+
209
+ ctx.schema.after_lazy(arguments) do |resolved_arguments|
210
+ if resolved_arguments.is_a?(GraphQL::Error)
211
+ raise resolved_arguments
207
212
  else
208
- nil
209
- end
210
- # Only continue if some value was found for this argument
211
- if has_value
212
- coerced_value = argument_defn.type.coerce_input(field_value, ctx)
213
- prepared_value = argument_defn.prepare_value(nil, coerced_value, context: ctx)
214
- input_values[arg_key] = prepared_value
213
+ input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
214
+ input_obj_instance.prepare
215
215
  end
216
216
  end
217
-
218
- input_values
219
217
  end
220
218
 
221
219
  # It's funny to think of a _result_ of an input object.
222
220
  # This is used for rendering the default value in introspection responses.
223
221
  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 }
222
+ # Allow the application to provide values as :snake_symbols, and convert them to the camelStrings
223
+ value = value.reduce({}) { |memo, (k, v)| memo[Member::BuildType.camelize(k.to_s)] = v; memo }
226
224
 
227
225
  result = {}
228
226
 
229
- arguments.each do |input_key, input_field_defn|
227
+ arguments(ctx).each do |input_key, input_field_defn|
230
228
  input_value = value[input_key]
231
229
  if value.key?(input_key)
232
230
  result[input_key] = if input_value.nil?
@@ -240,6 +238,16 @@ module GraphQL
240
238
  result
241
239
  end
242
240
  end
241
+
242
+ private
243
+
244
+ def overwrite_argument(key, value)
245
+ # Argument keywords come in frozen from the interpreter, dup them before modifying them.
246
+ if @ruby_style_hash.frozen?
247
+ @ruby_style_hash = @ruby_style_hash.dup
248
+ end
249
+ @ruby_style_hash[key] = value
250
+ end
243
251
  end
244
252
  end
245
253
  end
@@ -14,6 +14,9 @@ module GraphQL
14
14
  include GraphQL::Schema::Member::RelayShortcuts
15
15
  include GraphQL::Schema::Member::Scoped
16
16
  include GraphQL::Schema::Member::HasAstNode
17
+ include GraphQL::Schema::Member::HasUnresolvedTypeError
18
+ include GraphQL::Schema::Member::HasDirectives
19
+ include GraphQL::Schema::Member::HasInterfaces
17
20
 
18
21
  # Methods defined in this block will be:
19
22
  # - Added as class methods to this interface
@@ -29,7 +32,7 @@ module GraphQL
29
32
 
30
33
  # The interface is accessible if any of its possible types are accessible
31
34
  def accessible?(context)
32
- context.schema.possible_types(self).each do |type|
35
+ context.schema.possible_types(self, context).each do |type|
33
36
  if context.schema.accessible?(type, context)
34
37
  return true
35
38
  end
@@ -37,6 +40,14 @@ module GraphQL
37
40
  false
38
41
  end
39
42
 
43
+ def type_membership_class(membership_class = nil)
44
+ if membership_class
45
+ @type_membership_class = membership_class
46
+ else
47
+ @type_membership_class || find_inherited_value(:type_membership_class, GraphQL::Schema::TypeMembership)
48
+ end
49
+ end
50
+
40
51
  # Here's the tricky part. Make sure behavior keeps making its way down the inheritance chain.
41
52
  def included(child_class)
42
53
  if !child_class.is_a?(Class)
@@ -46,9 +57,11 @@ module GraphQL
46
57
  # We need this before we can call `own_interfaces`
47
58
  child_class.extend(Schema::Interface::DefinitionMethods)
48
59
 
49
- child_class.own_interfaces << self
50
- child_class.interfaces.reverse_each do |interface_defn|
51
- child_class.extend(interface_defn::DefinitionMethods)
60
+ child_class.type_membership_class(self.type_membership_class)
61
+ child_class.ancestors.reverse_each do |ancestor|
62
+ if ancestor.const_defined?(:DefinitionMethods)
63
+ child_class.extend(ancestor::DefinitionMethods)
64
+ end
52
65
  end
53
66
 
54
67
  # Use an instance variable to tell whether it's been included previously or not;
@@ -62,12 +75,13 @@ module GraphQL
62
75
  end
63
76
  child_class.introspection(introspection)
64
77
  child_class.description(description)
65
- if overridden_graphql_name
66
- child_class.graphql_name(overridden_graphql_name)
78
+ # If interfaces are mixed into each other, only define this class once
79
+ if !child_class.const_defined?(:UnresolvedTypeError, false)
80
+ add_unresolved_type_error(child_class)
67
81
  end
68
82
  elsif child_class < GraphQL::Schema::Object
69
83
  # This is being included into an object type, make sure it's using `implements(...)`
70
- 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'")}
71
85
  if !backtrace_line
72
86
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
73
87
  end
@@ -91,10 +105,11 @@ module GraphQL
91
105
  type_defn.name = graphql_name
92
106
  type_defn.description = description
93
107
  type_defn.orphan_types = orphan_types
108
+ type_defn.type_membership_class = self.type_membership_class
94
109
  type_defn.ast_node = ast_node
95
- fields.each do |field_name, field_inst|
110
+ fields.each do |field_name, field_inst| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
96
111
  field_defn = field_inst.graphql_definition
97
- type_defn.fields[field_defn.name] = field_defn
112
+ type_defn.fields[field_defn.name] = field_defn # rubocop:disable Development/ContextIsPassedCop -- legacy-related
98
113
  end
99
114
  type_defn.metadata[:type_class] = self
100
115
  if respond_to?(:resolve_type)
@@ -106,16 +121,6 @@ module GraphQL
106
121
  def kind
107
122
  GraphQL::TypeKinds::INTERFACE
108
123
  end
109
-
110
- protected
111
-
112
- def own_interfaces
113
- @own_interfaces ||= []
114
- end
115
-
116
- def interfaces
117
- own_interfaces + (own_interfaces.map { |i| i.own_interfaces }).flatten
118
- end
119
124
  end
120
125
 
121
126
  # Extend this _after_ `DefinitionMethods` is defined, so it will be used
@@ -16,11 +16,11 @@ module GraphQL
16
16
  end
17
17
 
18
18
  def to_non_null_type
19
- GraphQL::NonNullType.new(of_type: self)
19
+ @to_non_null_type ||= GraphQL::NonNullType.new(of_type: self)
20
20
  end
21
21
 
22
22
  def to_list_type
23
- GraphQL::ListType.new(of_type: self)
23
+ @to_list_type ||= GraphQL::ListType.new(of_type: self)
24
24
  end
25
25
 
26
26
  def inspect
@@ -31,6 +31,11 @@ module GraphQL
31
31
  nil
32
32
  end
33
33
 
34
+ # Also for implementing introspection
35
+ def description
36
+ nil
37
+ end
38
+
34
39
  def coerce_result(value, ctx)
35
40
  value.map { |i| i.nil? ? nil : of_type.coerce_result(i, ctx) }
36
41
  end
@@ -39,7 +44,8 @@ module GraphQL
39
44
  if value.nil?
40
45
  nil
41
46
  else
42
- ensure_array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
47
+ coerced = ensure_array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
48
+ ctx.schema.after_any_lazies(coerced, &:itself)
43
49
  end
44
50
  end
45
51