graphql 1.10.1 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
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