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
@@ -9,6 +9,13 @@ module GraphQL
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
11
  class << self
12
+ # Directives aren't types, they don't have kinds.
13
+ undef_method :kind
14
+
15
+ def path
16
+ "@#{super}"
17
+ end
18
+
12
19
  # Return a name based on the class name,
13
20
  # but downcase the first letter.
14
21
  def default_graphql_name
@@ -21,6 +28,11 @@ module GraphQL
21
28
 
22
29
  def locations(*new_locations)
23
30
  if new_locations.any?
31
+ new_locations.each do |new_loc|
32
+ if !LOCATIONS.include?(new_loc.to_sym)
33
+ raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
34
+ end
35
+ end
24
36
  @locations = new_locations
25
37
  else
26
38
  @locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
@@ -49,9 +61,9 @@ module GraphQL
49
61
  defn.default_directive = self.default_directive
50
62
  defn.ast_node = ast_node
51
63
  defn.metadata[:type_class] = self
52
- arguments.each do |name, arg_defn|
64
+ all_argument_definitions.each do |arg_defn|
53
65
  arg_graphql = arg_defn.to_graphql
54
- defn.arguments[arg_graphql.name] = arg_graphql
66
+ defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
55
67
  end
56
68
  # Make a reference to a classic-style Arguments class
57
69
  defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(defn)
@@ -87,6 +99,23 @@ module GraphQL
87
99
  end
88
100
  end
89
101
 
102
+ # @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
103
+ attr_reader :owner
104
+
105
+ # @return [GraphQL::Interpreter::Arguments]
106
+ attr_reader :arguments
107
+
108
+ def initialize(owner, **arguments)
109
+ @owner = owner
110
+ assert_valid_owner
111
+ # It's be nice if we had the real context here, but we don't. What we _would_ get is:
112
+ # - error handling
113
+ # - lazy resolution
114
+ # Probably, those won't be needed here, since these are configuration arguments,
115
+ # not runtime arguments.
116
+ @arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
117
+ end
118
+
90
119
  LOCATIONS = [
91
120
  QUERY = :QUERY,
92
121
  MUTATION = :MUTATION,
@@ -129,6 +158,53 @@ module GraphQL
129
158
  INPUT_OBJECT: 'Location adjacent to an input object type definition.',
130
159
  INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
131
160
  }
161
+
162
+ private
163
+
164
+ def assert_valid_owner
165
+ case @owner
166
+ when Class
167
+ if @owner < GraphQL::Schema::Object
168
+ assert_has_location(OBJECT)
169
+ elsif @owner < GraphQL::Schema::Union
170
+ assert_has_location(UNION)
171
+ elsif @owner < GraphQL::Schema::Enum
172
+ assert_has_location(ENUM)
173
+ elsif @owner < GraphQL::Schema::InputObject
174
+ assert_has_location(INPUT_OBJECT)
175
+ elsif @owner < GraphQL::Schema::Scalar
176
+ assert_has_location(SCALAR)
177
+ elsif @owner < GraphQL::Schema
178
+ assert_has_location(SCHEMA)
179
+ else
180
+ raise "Unexpected directive owner class: #{@owner}"
181
+ end
182
+ when Module
183
+ assert_has_location(INTERFACE)
184
+ when GraphQL::Schema::Argument
185
+ if @owner.owner.is_a?(GraphQL::Schema::Field)
186
+ assert_has_location(ARGUMENT_DEFINITION)
187
+ else
188
+ assert_has_location(INPUT_FIELD_DEFINITION)
189
+ end
190
+ when GraphQL::Schema::Field
191
+ assert_has_location(FIELD_DEFINITION)
192
+ when GraphQL::Schema::EnumValue
193
+ assert_has_location(ENUM_VALUE)
194
+ else
195
+ raise "Unexpected directive owner: #{@owner.inspect}"
196
+ end
197
+ end
198
+
199
+ def assert_has_location(location)
200
+ if !self.class.locations.include?(location)
201
+ raise ArgumentError, <<-MD
202
+ Directive `@#{self.class.graphql_name}` can't be attached to #{@owner.graphql_name} because #{location} isn't included in its locations (#{self.class.locations.join(", ")}).
203
+
204
+ Use `locations(#{location})` to update this directive's definition, or remove it from #{@owner.graphql_name}.
205
+ MD
206
+ end
207
+ end
132
208
  end
133
209
  end
134
210
  end
@@ -23,6 +23,18 @@ module GraphQL
23
23
  extend GraphQL::Schema::Member::AcceptsDefinition
24
24
  extend GraphQL::Schema::Member::ValidatesInput
25
25
 
26
+ class UnresolvedValueError < GraphQL::EnumType::UnresolvedValueError
27
+ def initialize(value:, enum:, context:)
28
+ fix_message = ", but this isn't a valid value for `#{enum.graphql_name}`. Update the field or resolver to return one of `#{enum.graphql_name}`'s values instead."
29
+ message = if (cp = context[:current_path]) && (cf = context[:current_field])
30
+ "`#{cf.path}` returned `#{value.inspect}` at `#{cp.join(".")}`#{fix_message}"
31
+ else
32
+ "`#{value.inspect}` was returned for `#{enum.graphql_name}`#{fix_message}"
33
+ end
34
+ super(message)
35
+ end
36
+ end
37
+
26
38
  class << self
27
39
  # Define a value for this enum
28
40
  # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
@@ -34,15 +46,66 @@ module GraphQL
34
46
  def value(*args, **kwargs, &block)
35
47
  kwargs[:owner] = self
36
48
  value = enum_value_class.new(*args, **kwargs, &block)
37
- own_values[value.graphql_name] = value
38
- nil
49
+ key = value.graphql_name
50
+ prev_value = own_values[key]
51
+ case prev_value
52
+ when nil
53
+ own_values[key] = value
54
+ when GraphQL::Schema::EnumValue
55
+ own_values[key] = [prev_value, value]
56
+ when Array
57
+ prev_value << value
58
+ else
59
+ raise "Invariant: Unexpected enum value for #{key.inspect}: #{prev_value.inspect}"
60
+ end
61
+ value
39
62
  end
40
63
 
41
- # @return [Hash<String => GraphQL::Schema::Enum::Value>] Possible values of this enum, keyed by name
42
- def values
43
- inherited_values = superclass <= GraphQL::Schema::Enum ? superclass.values : {}
44
- # Local values take precedence over inherited ones
45
- inherited_values.merge(own_values)
64
+ # @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
65
+ def enum_values(context = GraphQL::Query::NullContext)
66
+ inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
67
+ visible_values = []
68
+ warden = Warden.from_context(context)
69
+ own_values.each do |key, values_entry|
70
+ if (v = Warden.visible_entry?(:visible_enum_value?, values_entry, context, warden))
71
+ visible_values << v
72
+ end
73
+ end
74
+
75
+ if inherited_values
76
+ # Local values take precedence over inherited ones
77
+ inherited_values.each do |i_val|
78
+ if !visible_values.any? { |v| v.graphql_name == i_val.graphql_name }
79
+ visible_values << i_val
80
+ end
81
+ end
82
+ end
83
+
84
+ visible_values
85
+ end
86
+
87
+ # @return [Array<Schema::EnumValue>] An unfiltered list of all definitions
88
+ def all_enum_value_definitions
89
+ all_defns = if superclass.respond_to?(:all_enum_value_definitions)
90
+ superclass.all_enum_value_definitions
91
+ else
92
+ []
93
+ end
94
+
95
+ @own_values && @own_values.each do |_key, value|
96
+ if value.is_a?(Array)
97
+ all_defns.concat(value)
98
+ else
99
+ all_defns << value
100
+ end
101
+ end
102
+
103
+ all_defns
104
+ end
105
+
106
+ # @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
107
+ def values(context = GraphQL::Query::NullContext)
108
+ enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
46
109
  end
47
110
 
48
111
  # @return [GraphQL::EnumType]
@@ -63,8 +126,11 @@ module GraphQL
63
126
  def enum_value_class(new_enum_value_class = nil)
64
127
  if new_enum_value_class
65
128
  @enum_value_class = new_enum_value_class
129
+ elsif defined?(@enum_value_class) && @enum_value_class
130
+ @enum_value_class
131
+ else
132
+ superclass <= GraphQL::Schema::Enum ? superclass.enum_value_class : nil
66
133
  end
67
- @enum_value_class || (superclass <= GraphQL::Schema::Enum ? superclass.enum_value_class : nil)
68
134
  end
69
135
 
70
136
  def kind
@@ -91,7 +157,7 @@ module GraphQL
91
157
  if enum_value
92
158
  enum_value.graphql_name
93
159
  else
94
- raise(GraphQL::EnumType::UnresolvedValueError, "Can't resolve enum #{graphql_name} for #{value.inspect}")
160
+ raise self::UnresolvedValueError.new(enum: self, value: value, context: ctx)
95
161
  end
96
162
  end
97
163
 
@@ -109,6 +175,11 @@ module GraphQL
109
175
  end
110
176
  end
111
177
 
178
+ def inherited(child_class)
179
+ child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
180
+ super
181
+ end
182
+
112
183
  private
113
184
 
114
185
  def own_values
@@ -30,22 +30,29 @@ module GraphQL
30
30
  include GraphQL::Schema::Member::AcceptsDefinition
31
31
  include GraphQL::Schema::Member::HasPath
32
32
  include GraphQL::Schema::Member::HasAstNode
33
+ include GraphQL::Schema::Member::HasDirectives
34
+ include GraphQL::Schema::Member::HasDeprecationReason
33
35
 
34
36
  attr_reader :graphql_name
35
37
 
36
38
  # @return [Class] The enum type that owns this value
37
39
  attr_reader :owner
38
40
 
39
- # @return [String] Explains why this value was deprecated (if present, this will be marked deprecated in introspection)
40
- attr_accessor :deprecation_reason
41
-
42
- def initialize(graphql_name, desc = nil, owner:, ast_node: nil, description: nil, value: nil, deprecation_reason: nil, &block)
41
+ def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: nil, deprecation_reason: nil, &block)
43
42
  @graphql_name = graphql_name.to_s
43
+ GraphQL::NameValidator.validate!(@graphql_name)
44
44
  @description = desc || description
45
45
  @value = value.nil? ? @graphql_name : value
46
- @deprecation_reason = deprecation_reason
46
+ if deprecation_reason
47
+ self.deprecation_reason = deprecation_reason
48
+ end
47
49
  @owner = owner
48
50
  @ast_node = ast_node
51
+ if directives
52
+ directives.each do |dir_class, dir_options|
53
+ directive(dir_class, **dir_options)
54
+ end
55
+ end
49
56
 
50
57
  if block_given?
51
58
  instance_eval(&block)
@@ -72,12 +79,16 @@ module GraphQL
72
79
  enum_value.name = @graphql_name
73
80
  enum_value.description = @description
74
81
  enum_value.value = @value
75
- enum_value.deprecation_reason = @deprecation_reason
82
+ enum_value.deprecation_reason = self.deprecation_reason
76
83
  enum_value.metadata[:type_class] = self
77
84
  enum_value.ast_node = ast_node
78
85
  enum_value
79
86
  end
80
87
 
88
+ def inspect
89
+ "#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}>"
90
+ end
91
+
81
92
  def visible?(_ctx); true; end
82
93
  def accessible?(_ctx); true; end
83
94
  def authorized?(_ctx); true; end
@@ -18,40 +18,56 @@ module GraphQL
18
18
  next_args.delete(:last)
19
19
  next_args.delete(:before)
20
20
  next_args.delete(:after)
21
- yield(object, next_args)
21
+ yield(object, next_args, arguments)
22
22
  end
23
23
 
24
24
  def after_resolve(value:, object:, arguments:, context:, memo:)
25
- if value.is_a? GraphQL::ExecutionError
26
- # This isn't even going to work because context doesn't have ast_node anymore
27
- context.add_error(value)
28
- nil
29
- elsif value.nil?
30
- nil
31
- elsif value.is_a?(GraphQL::Pagination::Connection)
32
- # update the connection with some things that may not have been provided
33
- value.context ||= context
34
- value.first_value ||= arguments[:first]
35
- value.after_value ||= arguments[:after]
36
- value.last_value ||= arguments[:last]
37
- value.before_value ||= arguments[:before]
38
- value.max_page_size ||= field.max_page_size
39
- value
40
- elsif context.schema.new_connections?
41
- context.schema.connections.wrap(field, value, arguments, context)
42
- else
43
- if object.is_a?(GraphQL::Schema::Object)
44
- object = object.object
25
+ original_arguments = memo
26
+ # rename some inputs to avoid conflicts inside the block
27
+ maybe_lazy = value
28
+ value = nil
29
+ context.schema.after_lazy(maybe_lazy) do |resolved_value|
30
+ value = resolved_value
31
+ if value.is_a? GraphQL::ExecutionError
32
+ # This isn't even going to work because context doesn't have ast_node anymore
33
+ context.add_error(value)
34
+ nil
35
+ elsif value.nil?
36
+ nil
37
+ elsif value.is_a?(GraphQL::Pagination::Connection)
38
+ # update the connection with some things that may not have been provided
39
+ value.context ||= context
40
+ value.parent ||= object.object
41
+ value.first_value ||= original_arguments[:first]
42
+ value.after_value ||= original_arguments[:after]
43
+ value.last_value ||= original_arguments[:last]
44
+ value.before_value ||= original_arguments[:before]
45
+ value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
46
+ value.field ||= field
47
+ if field.has_max_page_size? && !value.has_max_page_size_override?
48
+ value.max_page_size = field.max_page_size
49
+ end
50
+ if context.schema.new_connections? && (custom_t = context.schema.connections.edge_class_for_field(@field))
51
+ value.edge_class = custom_t
52
+ end
53
+ value
54
+ elsif context.schema.new_connections?
55
+ context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
56
+ context.schema.connections.wrap(field, object.object, value, original_arguments, context)
57
+ else
58
+ if object.is_a?(GraphQL::Schema::Object)
59
+ object = object.object
60
+ end
61
+ connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
62
+ connection_class.new(
63
+ value,
64
+ original_arguments,
65
+ field: field,
66
+ max_page_size: field.max_page_size,
67
+ parent: object,
68
+ context: context,
69
+ )
45
70
  end
46
- connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
47
- connection_class.new(
48
- value,
49
- arguments,
50
- field: field,
51
- max_page_size: field.max_page_size,
52
- parent: object,
53
- context: context,
54
- )
55
71
  end
56
72
  end
57
73
  end
@@ -4,7 +4,7 @@ module GraphQL
4
4
  class Schema
5
5
  class Field
6
6
  class ScopeExtension < GraphQL::Schema::FieldExtension
7
- def after_resolve(value:, context:, **rest)
7
+ def after_resolve(object:, arguments:, context:, value:, memo:)
8
8
  if value.nil?
9
9
  value
10
10
  else