graphql 1.13.19 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (256) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/relay.rb +3 -17
  4. data/lib/generators/graphql/templates/schema.erb +3 -0
  5. data/lib/graphql/analysis/ast/field_usage.rb +3 -1
  6. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  7. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  8. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  9. data/lib/graphql/analysis/ast/visitor.rb +43 -36
  10. data/lib/graphql/analysis/ast.rb +2 -12
  11. data/lib/graphql/analysis.rb +0 -7
  12. data/lib/graphql/backtrace/table.rb +2 -20
  13. data/lib/graphql/backtrace/tracer.rb +2 -3
  14. data/lib/graphql/backtrace.rb +2 -8
  15. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  16. data/lib/graphql/dataloader/source.rb +9 -0
  17. data/lib/graphql/dataloader.rb +4 -1
  18. data/lib/graphql/dig.rb +1 -1
  19. data/lib/graphql/execution/errors.rb +12 -82
  20. data/lib/graphql/execution/interpreter/resolve.rb +26 -0
  21. data/lib/graphql/execution/interpreter/runtime.rb +162 -119
  22. data/lib/graphql/execution/interpreter.rb +187 -78
  23. data/lib/graphql/execution/lazy.rb +7 -21
  24. data/lib/graphql/execution/lookahead.rb +44 -40
  25. data/lib/graphql/execution/multiplex.rb +3 -174
  26. data/lib/graphql/execution.rb +11 -4
  27. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  28. data/lib/graphql/introspection/entry_points.rb +2 -15
  29. data/lib/graphql/introspection/type_type.rb +8 -1
  30. data/lib/graphql/introspection.rb +4 -3
  31. data/lib/graphql/language/document_from_schema_definition.rb +18 -35
  32. data/lib/graphql/language/lexer.rb +216 -1488
  33. data/lib/graphql/language/lexer.ri +744 -0
  34. data/lib/graphql/language/nodes.rb +41 -33
  35. data/lib/graphql/language/parser.rb +375 -363
  36. data/lib/graphql/language/parser.y +48 -43
  37. data/lib/graphql/language/printer.rb +37 -21
  38. data/lib/graphql/language/visitor.rb +191 -83
  39. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  40. data/lib/graphql/pagination/array_connection.rb +4 -2
  41. data/lib/graphql/pagination/connection.rb +31 -4
  42. data/lib/graphql/pagination/connections.rb +3 -28
  43. data/lib/graphql/pagination/relation_connection.rb +2 -0
  44. data/lib/graphql/query/context.rb +155 -196
  45. data/lib/graphql/query/input_validation_result.rb +1 -1
  46. data/lib/graphql/query/null_context.rb +0 -3
  47. data/lib/graphql/query/validation_pipeline.rb +10 -34
  48. data/lib/graphql/query/variables.rb +7 -20
  49. data/lib/graphql/query.rb +32 -42
  50. data/lib/graphql/railtie.rb +0 -104
  51. data/lib/graphql/rake_task/validate.rb +1 -1
  52. data/lib/graphql/rake_task.rb +29 -1
  53. data/lib/graphql/relay/range_add.rb +9 -20
  54. data/lib/graphql/relay.rb +0 -15
  55. data/lib/graphql/schema/addition.rb +7 -9
  56. data/lib/graphql/schema/argument.rb +36 -43
  57. data/lib/graphql/schema/build_from_definition.rb +32 -18
  58. data/lib/graphql/schema/directive/one_of.rb +12 -0
  59. data/lib/graphql/schema/directive/transform.rb +1 -1
  60. data/lib/graphql/schema/directive.rb +11 -22
  61. data/lib/graphql/schema/enum.rb +28 -39
  62. data/lib/graphql/schema/enum_value.rb +5 -25
  63. data/lib/graphql/schema/field/connection_extension.rb +4 -0
  64. data/lib/graphql/schema/field.rb +214 -327
  65. data/lib/graphql/schema/input_object.rb +56 -67
  66. data/lib/graphql/schema/interface.rb +0 -35
  67. data/lib/graphql/schema/introspection_system.rb +3 -8
  68. data/lib/graphql/schema/late_bound_type.rb +8 -2
  69. data/lib/graphql/schema/list.rb +0 -6
  70. data/lib/graphql/schema/loader.rb +1 -2
  71. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  72. data/lib/graphql/schema/member/build_type.rb +5 -7
  73. data/lib/graphql/schema/member/has_arguments.rb +144 -53
  74. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  75. data/lib/graphql/schema/member/has_directives.rb +71 -56
  76. data/lib/graphql/schema/member/has_fields.rb +15 -3
  77. data/lib/graphql/schema/member/has_interfaces.rb +47 -18
  78. data/lib/graphql/schema/member/has_validators.rb +31 -5
  79. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  80. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  81. data/lib/graphql/schema/member/validates_input.rb +1 -1
  82. data/lib/graphql/schema/member.rb +0 -6
  83. data/lib/graphql/schema/mutation.rb +0 -9
  84. data/lib/graphql/schema/non_null.rb +1 -7
  85. data/lib/graphql/schema/object.rb +15 -52
  86. data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
  87. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  88. data/lib/graphql/schema/resolver.rb +41 -42
  89. data/lib/graphql/schema/scalar.rb +7 -22
  90. data/lib/graphql/schema/subscription.rb +0 -7
  91. data/lib/graphql/schema/timeout.rb +24 -28
  92. data/lib/graphql/schema/type_membership.rb +3 -0
  93. data/lib/graphql/schema/union.rb +10 -17
  94. data/lib/graphql/schema/warden.rb +23 -6
  95. data/lib/graphql/schema/wrapper.rb +0 -5
  96. data/lib/graphql/schema.rb +240 -968
  97. data/lib/graphql/static_validation/all_rules.rb +1 -0
  98. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  99. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  100. data/lib/graphql/static_validation/error.rb +2 -2
  101. data/lib/graphql/static_validation/literal_validator.rb +19 -1
  102. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  103. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  104. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  105. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  106. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
  107. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  108. data/lib/graphql/static_validation/validator.rb +3 -25
  109. data/lib/graphql/static_validation.rb +0 -2
  110. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
  111. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  112. data/lib/graphql/subscriptions/event.rb +3 -8
  113. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  114. data/lib/graphql/subscriptions.rb +32 -20
  115. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  116. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  117. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  118. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  119. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  120. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  121. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  122. data/lib/graphql/tracing/platform_trace.rb +107 -0
  123. data/lib/graphql/tracing/platform_tracing.rb +26 -41
  124. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  125. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  126. data/lib/graphql/tracing/scout_trace.rb +72 -0
  127. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  128. data/lib/graphql/tracing.rb +136 -40
  129. data/lib/graphql/type_kinds.rb +6 -3
  130. data/lib/graphql/types/iso_8601_date.rb +4 -1
  131. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  132. data/lib/graphql/types/relay/base_connection.rb +16 -6
  133. data/lib/graphql/types/relay/connection_behaviors.rb +5 -25
  134. data/lib/graphql/types/relay/default_relay.rb +5 -9
  135. data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
  136. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  137. data/lib/graphql/types/relay.rb +0 -2
  138. data/lib/graphql/types/string.rb +1 -1
  139. data/lib/graphql/version.rb +1 -1
  140. data/lib/graphql.rb +11 -72
  141. metadata +31 -132
  142. data/lib/graphql/analysis/analyze_query.rb +0 -98
  143. data/lib/graphql/analysis/field_usage.rb +0 -45
  144. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  145. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  146. data/lib/graphql/analysis/query_complexity.rb +0 -88
  147. data/lib/graphql/analysis/query_depth.rb +0 -43
  148. data/lib/graphql/analysis/reducer_state.rb +0 -48
  149. data/lib/graphql/argument.rb +0 -131
  150. data/lib/graphql/authorization.rb +0 -82
  151. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  152. data/lib/graphql/backwards_compatibility.rb +0 -61
  153. data/lib/graphql/base_type.rb +0 -232
  154. data/lib/graphql/boolean_type.rb +0 -2
  155. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  156. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  157. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  158. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  159. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  160. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  161. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  162. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  163. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  164. data/lib/graphql/compatibility.rb +0 -5
  165. data/lib/graphql/define/assign_argument.rb +0 -12
  166. data/lib/graphql/define/assign_connection.rb +0 -13
  167. data/lib/graphql/define/assign_enum_value.rb +0 -18
  168. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  169. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  170. data/lib/graphql/define/assign_object_field.rb +0 -42
  171. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  172. data/lib/graphql/define/instance_definable.rb +0 -255
  173. data/lib/graphql/define/no_definition_error.rb +0 -7
  174. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  175. data/lib/graphql/define/type_definer.rb +0 -31
  176. data/lib/graphql/define.rb +0 -31
  177. data/lib/graphql/deprecated_dsl.rb +0 -55
  178. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  179. data/lib/graphql/directive/include_directive.rb +0 -2
  180. data/lib/graphql/directive/skip_directive.rb +0 -2
  181. data/lib/graphql/directive.rb +0 -107
  182. data/lib/graphql/enum_type.rb +0 -133
  183. data/lib/graphql/execution/execute.rb +0 -333
  184. data/lib/graphql/execution/flatten.rb +0 -40
  185. data/lib/graphql/execution/instrumentation.rb +0 -92
  186. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  187. data/lib/graphql/execution/typecast.rb +0 -50
  188. data/lib/graphql/field/resolve.rb +0 -59
  189. data/lib/graphql/field.rb +0 -226
  190. data/lib/graphql/float_type.rb +0 -2
  191. data/lib/graphql/function.rb +0 -128
  192. data/lib/graphql/id_type.rb +0 -2
  193. data/lib/graphql/input_object_type.rb +0 -138
  194. data/lib/graphql/int_type.rb +0 -2
  195. data/lib/graphql/interface_type.rb +0 -72
  196. data/lib/graphql/internal_representation/document.rb +0 -27
  197. data/lib/graphql/internal_representation/node.rb +0 -206
  198. data/lib/graphql/internal_representation/print.rb +0 -51
  199. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  200. data/lib/graphql/internal_representation/scope.rb +0 -88
  201. data/lib/graphql/internal_representation/visit.rb +0 -36
  202. data/lib/graphql/internal_representation.rb +0 -7
  203. data/lib/graphql/language/lexer.rl +0 -260
  204. data/lib/graphql/list_type.rb +0 -80
  205. data/lib/graphql/non_null_type.rb +0 -71
  206. data/lib/graphql/object_type.rb +0 -130
  207. data/lib/graphql/query/arguments.rb +0 -189
  208. data/lib/graphql/query/arguments_cache.rb +0 -24
  209. data/lib/graphql/query/executor.rb +0 -52
  210. data/lib/graphql/query/literal_input.rb +0 -136
  211. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  212. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  213. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  214. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  215. data/lib/graphql/query/serial_execution.rb +0 -40
  216. data/lib/graphql/relay/array_connection.rb +0 -83
  217. data/lib/graphql/relay/base_connection.rb +0 -189
  218. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  219. data/lib/graphql/relay/connection_resolve.rb +0 -43
  220. data/lib/graphql/relay/connection_type.rb +0 -54
  221. data/lib/graphql/relay/edge.rb +0 -27
  222. data/lib/graphql/relay/edge_type.rb +0 -19
  223. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  224. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  225. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  226. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  227. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  228. data/lib/graphql/relay/mutation/result.rb +0 -38
  229. data/lib/graphql/relay/mutation.rb +0 -106
  230. data/lib/graphql/relay/node.rb +0 -39
  231. data/lib/graphql/relay/page_info.rb +0 -7
  232. data/lib/graphql/relay/relation_connection.rb +0 -188
  233. data/lib/graphql/relay/type_extensions.rb +0 -32
  234. data/lib/graphql/scalar_type.rb +0 -91
  235. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  236. data/lib/graphql/schema/default_parse_error.rb +0 -10
  237. data/lib/graphql/schema/default_type_error.rb +0 -17
  238. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  239. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  240. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  241. data/lib/graphql/schema/middleware_chain.rb +0 -82
  242. data/lib/graphql/schema/possible_types.rb +0 -44
  243. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  244. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  245. data/lib/graphql/schema/traversal.rb +0 -228
  246. data/lib/graphql/schema/validation.rb +0 -313
  247. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  248. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  249. data/lib/graphql/string_type.rb +0 -2
  250. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  251. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  252. data/lib/graphql/types/relay/node_field.rb +0 -24
  253. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  254. data/lib/graphql/union_type.rb +0 -115
  255. data/lib/graphql/upgrader/member.rb +0 -937
  256. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -36,6 +36,7 @@ module GraphQL
36
36
  GraphQL::StaticValidation::QueryRootExists,
37
37
  GraphQL::StaticValidation::SubscriptionRootExists,
38
38
  GraphQL::StaticValidation::InputObjectNamesAreUnique,
39
+ GraphQL::StaticValidation::OneOfInputObjectsAreValid,
39
40
  ]
40
41
  end
41
42
  end
@@ -14,11 +14,6 @@ module GraphQL
14
14
  super(document)
15
15
  end
16
16
 
17
- # This will be overwritten by {InternalRepresentation::Rewrite} if it's included
18
- def rewrite_document
19
- nil
20
- end
21
-
22
17
  attr_reader :context
23
18
 
24
19
  # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
@@ -32,22 +27,13 @@ module GraphQL
32
27
  # Build a class to visit the AST and perform validation,
33
28
  # or use a pre-built class if rules is `ALL_RULES` or empty.
34
29
  # @param rules [Array<Module, Class>]
35
- # @param rewrite [Boolean] if `false`, don't include rewrite
36
30
  # @return [Class] A class for validating `rules` during visitation
37
- def self.including_rules(rules, rewrite: true)
31
+ def self.including_rules(rules)
38
32
  if rules.empty?
39
- if rewrite
40
- NoValidateVisitor
41
- else
42
- # It's not doing _anything?!?_
43
- BaseVisitor
44
- end
33
+ # It's not doing _anything?!?_
34
+ BaseVisitor
45
35
  elsif rules == ALL_RULES
46
- if rewrite
47
- DefaultVisitor
48
- else
49
- InterpreterVisitor
50
- end
36
+ InterpreterVisitor
51
37
  else
52
38
  visitor_class = Class.new(self) do
53
39
  include(GraphQL::StaticValidation::DefinitionDependencies)
@@ -60,9 +46,6 @@ module GraphQL
60
46
  end
61
47
  end
62
48
 
63
- if rewrite
64
- visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
65
- end
66
49
  visitor_class.include(ContextMethods)
67
50
  visitor_class
68
51
  end
@@ -127,8 +127,14 @@ module GraphQL
127
127
  # same name as if they were the same name. If _any_ of the fragments
128
128
  # with that name has a dependency, we record it.
129
129
  independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
130
-
130
+ visited_fragment_names = Set.new
131
131
  while fragment_node = independent_fragment_nodes.pop
132
+ if visited_fragment_names.add?(fragment_node.name)
133
+ # this is a new fragment name
134
+ else
135
+ # this is a duplicate fragment name
136
+ next
137
+ end
132
138
  loops += 1
133
139
  if loops > max_loops
134
140
  raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
@@ -30,10 +30,10 @@ module GraphQL
30
30
  }.tap { |h| h["path"] = path unless path.nil? }
31
31
  end
32
32
 
33
- private
34
-
35
33
  attr_reader :nodes
36
34
 
35
+ private
36
+
37
37
  def locations
38
38
  nodes.map do |node|
39
39
  h = {"line" => node.line, "column" => node.col}
@@ -18,6 +18,19 @@ module GraphQL
18
18
 
19
19
  private
20
20
 
21
+ def replace_nulls_in(ast_value)
22
+ case ast_value
23
+ when Array
24
+ ast_value.map { |v| replace_nulls_in(v) }
25
+ when GraphQL::Language::Nodes::InputObject
26
+ ast_value.to_h
27
+ when GraphQL::Language::Nodes::NullValue
28
+ nil
29
+ else
30
+ ast_value
31
+ end
32
+ end
33
+
21
34
  def recursively_validate(ast_value, type)
22
35
  if type.nil?
23
36
  # this means we're an undefined argument, see #present_input_field_values_are_valid
@@ -42,7 +55,8 @@ module GraphQL
42
55
  @valid_response
43
56
  elsif type.kind.scalar? && constant_scalar?(ast_value)
44
57
  maybe_raise_if_invalid(ast_value) do
45
- type.validate_input(ast_value, @context)
58
+ ruby_value = replace_nulls_in(ast_value)
59
+ type.validate_input(ruby_value, @context)
46
60
  end
47
61
  elsif type.kind.enum?
48
62
  maybe_raise_if_invalid(ast_value) do
@@ -108,6 +122,10 @@ module GraphQL
108
122
  arg_type = @warden.get_argument(type, name).type
109
123
  recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
110
124
  end
125
+
126
+ if type.one_of? && ast_node.arguments.size != 1
127
+ results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
128
+ end
111
129
  merge_results(results)
112
130
  end
113
131
  end
@@ -9,11 +9,17 @@ module GraphQL
9
9
 
10
10
  def on_directive(node, parent)
11
11
  if !@directive_names.include?(node.name)
12
- add_error(GraphQL::StaticValidation::DirectivesAreDefinedError.new(
13
- "Directive @#{node.name} is not defined",
14
- nodes: node,
15
- directive: node.name
16
- ))
12
+ @directives_are_defined_errors_by_name ||= {}
13
+ error = @directives_are_defined_errors_by_name[node.name] ||= begin
14
+ err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
15
+ "Directive @#{node.name} is not defined",
16
+ nodes: [],
17
+ directive: node.name
18
+ )
19
+ add_error(err)
20
+ err
21
+ end
22
+ error.nodes << node
17
23
  else
18
24
  super
19
25
  end
@@ -12,20 +12,20 @@ module GraphQL
12
12
  private
13
13
 
14
14
  LOCATION_MESSAGE_NAMES = {
15
- GraphQL::Directive::QUERY => "queries",
16
- GraphQL::Directive::MUTATION => "mutations",
17
- GraphQL::Directive::SUBSCRIPTION => "subscriptions",
18
- GraphQL::Directive::FIELD => "fields",
19
- GraphQL::Directive::FRAGMENT_DEFINITION => "fragment definitions",
20
- GraphQL::Directive::FRAGMENT_SPREAD => "fragment spreads",
21
- GraphQL::Directive::INLINE_FRAGMENT => "inline fragments",
15
+ GraphQL::Schema::Directive::QUERY => "queries",
16
+ GraphQL::Schema::Directive::MUTATION => "mutations",
17
+ GraphQL::Schema::Directive::SUBSCRIPTION => "subscriptions",
18
+ GraphQL::Schema::Directive::FIELD => "fields",
19
+ GraphQL::Schema::Directive::FRAGMENT_DEFINITION => "fragment definitions",
20
+ GraphQL::Schema::Directive::FRAGMENT_SPREAD => "fragment spreads",
21
+ GraphQL::Schema::Directive::INLINE_FRAGMENT => "inline fragments",
22
22
  }
23
23
 
24
24
  SIMPLE_LOCATIONS = {
25
- Nodes::Field => GraphQL::Directive::FIELD,
26
- Nodes::InlineFragment => GraphQL::Directive::INLINE_FRAGMENT,
27
- Nodes::FragmentSpread => GraphQL::Directive::FRAGMENT_SPREAD,
28
- Nodes::FragmentDefinition => GraphQL::Directive::FRAGMENT_DEFINITION,
25
+ Nodes::Field => GraphQL::Schema::Directive::FIELD,
26
+ Nodes::InlineFragment => GraphQL::Schema::Directive::INLINE_FRAGMENT,
27
+ Nodes::FragmentSpread => GraphQL::Schema::Directive::FRAGMENT_SPREAD,
28
+ Nodes::FragmentDefinition => GraphQL::Schema::Directive::FRAGMENT_DEFINITION,
29
29
  }
30
30
 
31
31
  SIMPLE_LOCATION_NODES = SIMPLE_LOCATIONS.keys
@@ -34,7 +34,7 @@ module GraphQL
34
34
  directive_defn = directives[ast_directive.name]
35
35
  case ast_parent
36
36
  when Nodes::OperationDefinition
37
- required_location = GraphQL::Directive.const_get(ast_parent.operation_type.upcase)
37
+ required_location = GraphQL::Schema::Directive.const_get(ast_parent.operation_type.upcase)
38
38
  assert_includes_location(directive_defn, ast_directive, required_location)
39
39
  when *SIMPLE_LOCATION_NODES
40
40
  required_location = SIMPLE_LOCATIONS[ast_parent.class]
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ module OneOfInputObjectsAreValid
5
+ def on_input_object(node, parent)
6
+ return super unless parent.is_a?(GraphQL::Language::Nodes::Argument)
7
+
8
+ parent_type = get_parent_type(context, parent)
9
+ return super unless parent_type && parent_type.kind.input_object? && parent_type.one_of?
10
+
11
+ validate_one_of_input_object(node, context, parent_type)
12
+ super
13
+ end
14
+
15
+ private
16
+
17
+ def validate_one_of_input_object(ast_node, context, parent_type)
18
+ present_fields = ast_node.arguments.map(&:name)
19
+ input_object_type = parent_type.to_type_signature
20
+
21
+ if present_fields.count != 1
22
+ add_error(
23
+ OneOfInputObjectsAreValidError.new(
24
+ "OneOf Input Object '#{input_object_type}' must specify exactly one key.",
25
+ path: context.path,
26
+ nodes: ast_node,
27
+ input_object_type: input_object_type
28
+ )
29
+ )
30
+ return
31
+ end
32
+
33
+ field = present_fields.first
34
+ value = ast_node.arguments.first.value
35
+
36
+ if value.is_a?(GraphQL::Language::Nodes::NullValue)
37
+ add_error(
38
+ OneOfInputObjectsAreValidError.new(
39
+ "Argument '#{input_object_type}.#{field}' must be non-null.",
40
+ path: [*context.path, field],
41
+ nodes: ast_node.arguments.first,
42
+ input_object_type: input_object_type
43
+ )
44
+ )
45
+ return
46
+ end
47
+
48
+ if value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
49
+ variable_name = value.name
50
+ variable_type = @declared_variables[variable_name].type
51
+
52
+ unless variable_type.is_a?(GraphQL::Language::Nodes::NonNullType)
53
+ add_error(
54
+ OneOfInputObjectsAreValidError.new(
55
+ "Variable '#{variable_name}' must be non-nullable to be used for OneOf Input Object '#{input_object_type}'.",
56
+ path: [*context.path, field],
57
+ nodes: ast_node,
58
+ input_object_type: input_object_type
59
+ )
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class OneOfInputObjectsAreValidError < StaticValidation::Error
5
+ attr_reader :input_object_type
6
+
7
+ def initialize(message, path:, nodes:, input_object_type:)
8
+ super(message, path: path, nodes: nodes)
9
+ @input_object_type = input_object_type
10
+ end
11
+
12
+ # A hash representation of this Message
13
+ def to_h
14
+ extensions = {
15
+ "code" => code,
16
+ "inputObjectType" => input_object_type
17
+ }
18
+
19
+ super.merge({
20
+ "extensions" => extensions
21
+ })
22
+ end
23
+
24
+ def code
25
+ "invalidOneOfInputObject"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -34,12 +34,18 @@ module GraphQL
34
34
  used_directives = {}
35
35
  node.directives.each do |ast_directive|
36
36
  directive_name = ast_directive.name
37
- if used_directives[directive_name]
38
- add_error(GraphQL::StaticValidation::UniqueDirectivesPerLocationError.new(
39
- "The directive \"#{directive_name}\" can only be used once at this location.",
40
- nodes: [used_directives[directive_name], ast_directive],
41
- directive: directive_name,
42
- ))
37
+ if (first_node = used_directives[directive_name])
38
+ @directives_are_unique_errors_by_first_node ||= {}
39
+ err = @directives_are_unique_errors_by_first_node[first_node] ||= begin
40
+ error = GraphQL::StaticValidation::UniqueDirectivesPerLocationError.new(
41
+ "The directive \"#{directive_name}\" can only be used once at this location.",
42
+ nodes: [used_directives[directive_name]],
43
+ directive: directive_name,
44
+ )
45
+ add_error(error)
46
+ error
47
+ end
48
+ err.nodes << ast_directive
43
49
  elsif !((dir_defn = context.schema_directives[directive_name]) && dir_defn.repeatable?)
44
50
  used_directives[directive_name] = ast_directive
45
51
  end
@@ -23,7 +23,7 @@ module GraphQL
23
23
  problems = validation_result.problems
24
24
  first_problem = problems && problems.first
25
25
  if first_problem
26
- error_message = first_problem["message"]
26
+ error_message = first_problem["explanation"]
27
27
  end
28
28
 
29
29
  error_message ||= "Default value for $#{node.name} doesn't match type #{type.to_type_signature}"
@@ -27,13 +27,12 @@ module GraphQL
27
27
  # @param max_errors [Integer] Maximum number of errors before aborting validation. Any positive number will limit the number of errors. Defaults to nil for no limit.
28
28
  # @return [Array<Hash>]
29
29
  def validate(query, validate: true, timeout: nil, max_errors: nil)
30
- query.trace("validate", { validate: validate, query: query }) do
31
- can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis? && query.schema.is_a?(Class)
32
- errors = if validate == false && can_skip_rewrite
30
+ query.current_trace.validate(validate: validate, query: query) do
31
+ errors = if validate == false
33
32
  []
34
33
  else
35
34
  rules_to_use = validate ? @rules : []
36
- visitor_class = BaseVisitor.including_rules(rules_to_use, rewrite: !can_skip_rewrite)
35
+ visitor_class = BaseVisitor.including_rules(rules_to_use)
37
36
 
38
37
  context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class, max_errors)
39
38
 
@@ -42,18 +41,6 @@ module GraphQL
42
41
  # A timeout value of 0 or nil will execute the block without any timeout.
43
42
  Timeout::timeout(timeout) do
44
43
  catch(:too_many_validation_errors) do
45
- # Attach legacy-style rules.
46
- # Only loop through rules if it has legacy-style rules
47
- unless (legacy_rules = rules_to_use - GraphQL::StaticValidation::ALL_RULES).empty?
48
- legacy_rules.each do |rule_class_or_module|
49
- if rule_class_or_module.method_defined?(:validate)
50
- GraphQL::Deprecation.warn "Legacy validator rules will be removed from GraphQL-Ruby 2.0, use a module instead (see the built-in rules: https://github.com/rmosolgo/graphql-ruby/tree/master/lib/graphql/static_validation/rules)"
51
- GraphQL::Deprecation.warn " -> Legacy validator: #{rule_class_or_module}"
52
- rule_class_or_module.new.validate(context)
53
- end
54
- end
55
- end
56
-
57
44
  context.visitor.visit
58
45
  end
59
46
  end
@@ -64,22 +51,13 @@ module GraphQL
64
51
  context.errors
65
52
  end
66
53
 
67
- irep = if errors.empty? && context
68
- # Only return this if there are no errors and validation was actually run
69
- context.visitor.rewrite_document
70
- else
71
- nil
72
- end
73
-
74
54
  {
75
55
  errors: errors,
76
- irep: irep,
77
56
  }
78
57
  end
79
58
  rescue GraphQL::ExecutionError => e
80
59
  {
81
60
  errors: [e],
82
- irep: nil,
83
61
  }
84
62
  end
85
63
 
@@ -7,7 +7,6 @@ require "graphql/static_validation/validation_context"
7
7
  require "graphql/static_validation/validation_timeout_error"
8
8
  require "graphql/static_validation/literal_validator"
9
9
  require "graphql/static_validation/base_visitor"
10
- require "graphql/static_validation/no_validate_visitor"
11
10
 
12
11
  rules_glob = File.expand_path("../static_validation/rules/*.rb", __FILE__)
13
12
  Dir.glob(rules_glob).each do |file|
@@ -15,5 +14,4 @@ Dir.glob(rules_glob).each do |file|
15
14
  end
16
15
 
17
16
  require "graphql/static_validation/all_rules"
18
- require "graphql/static_validation/default_visitor"
19
17
  require "graphql/static_validation/interpreter_visitor"
@@ -91,7 +91,13 @@ module GraphQL
91
91
  # A per-process map of subscriptions to deliver.
92
92
  # This is provided by Rails, so let's use it
93
93
  @subscriptions = Concurrent::Map.new
94
- @events = Concurrent::Map.new { |h, k| h[k] = Concurrent::Map.new { |h2, k2| h2[k2] = Concurrent::Array.new } }
94
+ @events = Concurrent::Map.new do |h, k|
95
+ h.compute_if_absent(k) do
96
+ Concurrent::Map.new do |h2, k2|
97
+ h2.compute_if_absent(k2) { Concurrent::Array.new }
98
+ end
99
+ end
100
+ end
95
101
  @action_cable = action_cable
96
102
  @action_cable_coder = action_cable_coder
97
103
  @serializer = serializer
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  class Subscriptions
4
- class DefaultSubscriptionResolveExtension < GraphQL::Subscriptions::SubscriptionRoot::Extension
4
+ class DefaultSubscriptionResolveExtension < GraphQL::Schema::FieldExtension
5
5
  def resolve(context:, object:, arguments:)
6
6
  has_override_implementation = @field.resolver ||
7
7
  object.respond_to?(@field.resolver_method)
@@ -16,6 +16,43 @@ module GraphQL
16
16
  yield(object, arguments)
17
17
  end
18
18
  end
19
+
20
+ def after_resolve(value:, context:, object:, arguments:, **rest)
21
+ if value.is_a?(GraphQL::ExecutionError)
22
+ value
23
+ elsif (events = context.namespace(:subscriptions)[:events])
24
+ # This is the first execution, so gather an Event
25
+ # for the backend to register:
26
+ event = Subscriptions::Event.new(
27
+ name: field.name,
28
+ arguments: arguments_without_field_extras(arguments: arguments),
29
+ context: context,
30
+ field: field,
31
+ )
32
+ events << event
33
+ value
34
+ elsif context.query.subscription_topic == Subscriptions::Event.serialize(
35
+ field.name,
36
+ arguments_without_field_extras(arguments: arguments),
37
+ field,
38
+ scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
39
+ )
40
+ # This is a subscription update. The resolver returned `skip` if it should be skipped,
41
+ # or else it returned an object to resolve the update.
42
+ value
43
+ else
44
+ # This is a subscription update, but this event wasn't triggered.
45
+ context.skip
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def arguments_without_field_extras(arguments:)
52
+ arguments.dup.tap do |event_args|
53
+ field.extras.each { |k| event_args.delete(k) }
54
+ end
55
+ end
19
56
  end
20
57
  end
21
58
  end
@@ -9,7 +9,7 @@ module GraphQL
9
9
  # @return [String] Corresponds to the Subscription root field name
10
10
  attr_reader :name
11
11
 
12
- # @return [GraphQL::Query::Arguments]
12
+ # @return [GraphQL::Execution::Interpreter::Arguments]
13
13
  attr_reader :arguments
14
14
 
15
15
  # @return [GraphQL::Query::Context]
@@ -100,13 +100,8 @@ module GraphQL
100
100
  arg_name = k.to_s
101
101
  camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name)
102
102
  arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context)
103
-
104
- if arg_defn
105
- normalized_arg_name = camelized_arg_name
106
- else
107
- normalized_arg_name = arg_name
108
- arg_defn = get_arg_definition(arg_owner, normalized_arg_name, context)
109
- end
103
+ arg_defn ||= get_arg_definition(arg_owner, arg_name, context)
104
+ normalized_arg_name = arg_defn.graphql_name
110
105
  arg_base_type = arg_defn.type.unwrap
111
106
  # In the case where the value being emitted is seen as a "JSON"
112
107
  # type, treat the value as one atomic unit of serialization
@@ -9,16 +9,6 @@ module GraphQL
9
9
  @schema = schema
10
10
  end
11
11
 
12
- def instrument(type, field)
13
- if type == @schema.subscription.graphql_definition
14
- # This is a root field of `subscription`
15
- subscribing_resolve_proc = SubscriptionRegistrationResolve.new(field.resolve_proc)
16
- field.redefine(resolve: subscribing_resolve_proc)
17
- else
18
- field
19
- end
20
- end
21
-
22
12
  # If needed, prepare to gather events which this query subscribes to
23
13
  def before_query(query)
24
14
  if query.subscription? && !query.subscription_update?
@@ -33,47 +23,6 @@ module GraphQL
33
23
  @schema.subscriptions.write_subscription(query, events)
34
24
  end
35
25
  end
36
-
37
- private
38
-
39
- class SubscriptionRegistrationResolve
40
- def initialize(inner_proc)
41
- @inner_proc = inner_proc
42
- end
43
-
44
- # Wrap the proc with subscription registration logic
45
- def call(obj, args, ctx)
46
- result = nil
47
- if @inner_proc && !@inner_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
48
- result = @inner_proc.call(obj, args, ctx)
49
- end
50
-
51
- events = ctx.namespace(:subscriptions)[:events]
52
-
53
- if events
54
- # This is the first execution, so gather an Event
55
- # for the backend to register:
56
- events << Subscriptions::Event.new(
57
- name: ctx.field.name,
58
- arguments: args,
59
- context: ctx,
60
- )
61
- result
62
- elsif ctx.irep_node.subscription_topic == ctx.query.subscription_topic
63
- if !result.nil?
64
- result
65
- elsif obj.is_a?(GraphQL::Schema::Object)
66
- # The root object is _already_ the subscription update:
67
- obj.object
68
- else
69
- obj
70
- end
71
- else
72
- # This is a subscription update, but this event wasn't triggered.
73
- ctx.skip
74
- end
75
- end
76
- end
77
26
  end
78
27
  end
79
28
  end