graphql 1.9.0.pre1 → 1.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +5 -1
  3. data/lib/graphql/analysis/ast/analyzer.rb +1 -1
  4. data/lib/graphql/analysis/ast/visitor.rb +6 -1
  5. data/lib/graphql/backwards_compatibility.rb +1 -1
  6. data/lib/graphql/dig.rb +19 -0
  7. data/lib/graphql/directive.rb +13 -1
  8. data/lib/graphql/directive/include_directive.rb +1 -7
  9. data/lib/graphql/directive/skip_directive.rb +1 -8
  10. data/lib/graphql/execution/interpreter.rb +23 -13
  11. data/lib/graphql/execution/interpreter/resolve.rb +56 -0
  12. data/lib/graphql/execution/interpreter/runtime.rb +174 -74
  13. data/lib/graphql/execution/lazy.rb +7 -1
  14. data/lib/graphql/execution/lookahead.rb +71 -6
  15. data/lib/graphql/execution_error.rb +1 -1
  16. data/lib/graphql/introspection/entry_points.rb +5 -1
  17. data/lib/graphql/introspection/type_type.rb +4 -4
  18. data/lib/graphql/language.rb +0 -1
  19. data/lib/graphql/language/block_string.rb +37 -0
  20. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  21. data/lib/graphql/language/lexer.rb +55 -36
  22. data/lib/graphql/language/lexer.rl +8 -3
  23. data/lib/graphql/language/nodes.rb +27 -4
  24. data/lib/graphql/language/parser.rb +55 -55
  25. data/lib/graphql/language/parser.y +11 -11
  26. data/lib/graphql/language/printer.rb +1 -1
  27. data/lib/graphql/language/visitor.rb +22 -13
  28. data/lib/graphql/literal_validation_error.rb +6 -0
  29. data/lib/graphql/query.rb +13 -0
  30. data/lib/graphql/query/arguments.rb +2 -1
  31. data/lib/graphql/query/context.rb +3 -10
  32. data/lib/graphql/query/executor.rb +1 -1
  33. data/lib/graphql/query/validation_pipeline.rb +1 -1
  34. data/lib/graphql/relay/connection_resolve.rb +1 -1
  35. data/lib/graphql/relay/relation_connection.rb +1 -1
  36. data/lib/graphql/schema.rb +81 -11
  37. data/lib/graphql/schema/argument.rb +1 -1
  38. data/lib/graphql/schema/build_from_definition.rb +2 -4
  39. data/lib/graphql/schema/directive.rb +103 -0
  40. data/lib/graphql/schema/directive/feature.rb +66 -0
  41. data/lib/graphql/schema/directive/include.rb +25 -0
  42. data/lib/graphql/schema/directive/skip.rb +25 -0
  43. data/lib/graphql/schema/directive/transform.rb +48 -0
  44. data/lib/graphql/schema/enum_value.rb +2 -2
  45. data/lib/graphql/schema/field.rb +63 -17
  46. data/lib/graphql/schema/input_object.rb +1 -0
  47. data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
  48. data/lib/graphql/schema/member/build_type.rb +33 -1
  49. data/lib/graphql/schema/member/has_fields.rb +8 -73
  50. data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
  51. data/lib/graphql/schema/resolver.rb +1 -1
  52. data/lib/graphql/static_validation.rb +2 -1
  53. data/lib/graphql/static_validation/all_rules.rb +1 -0
  54. data/lib/graphql/static_validation/base_visitor.rb +25 -10
  55. data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
  56. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  57. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  58. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  59. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +34 -5
  60. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  61. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +2 -2
  62. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  63. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
  64. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  65. data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
  66. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  67. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +11 -2
  68. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  69. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +11 -2
  70. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -2
  72. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  73. data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
  74. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  75. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
  76. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  77. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -1
  78. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  79. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
  80. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  81. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
  82. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  83. data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
  84. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  85. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +5 -1
  86. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  87. data/lib/graphql/static_validation/rules/fragments_are_used.rb +13 -3
  88. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  89. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
  90. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  91. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
  92. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  93. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +9 -2
  94. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  95. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -1
  96. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  97. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  98. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  99. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +4 -1
  100. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  101. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
  102. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  103. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +20 -6
  104. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  105. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +5 -1
  106. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  107. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -1
  108. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  109. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -2
  110. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  111. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +18 -2
  112. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  113. data/lib/graphql/static_validation/validator.rb +24 -14
  114. data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
  115. data/lib/graphql/tracing/skylight_tracing.rb +2 -2
  116. data/lib/graphql/unauthorized_field_error.rb +23 -0
  117. data/lib/graphql/version.rb +1 -1
  118. data/spec/graphql/analysis/ast_spec.rb +40 -0
  119. data/spec/graphql/authorization_spec.rb +93 -20
  120. data/spec/graphql/base_type_spec.rb +3 -1
  121. data/spec/graphql/execution/interpreter_spec.rb +127 -4
  122. data/spec/graphql/execution/lazy_spec.rb +49 -0
  123. data/spec/graphql/execution/lookahead_spec.rb +113 -21
  124. data/spec/graphql/execution/multiplex_spec.rb +2 -1
  125. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  126. data/spec/graphql/language/lexer_spec.rb +72 -3
  127. data/spec/graphql/language/printer_spec.rb +18 -6
  128. data/spec/graphql/query/arguments_spec.rb +21 -0
  129. data/spec/graphql/query/context_spec.rb +10 -0
  130. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  131. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  132. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  133. data/spec/graphql/schema/enum_spec.rb +5 -3
  134. data/spec/graphql/schema/field_extension_spec.rb +3 -3
  135. data/spec/graphql/schema/field_spec.rb +19 -0
  136. data/spec/graphql/schema/input_object_spec.rb +81 -0
  137. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  138. data/spec/graphql/schema/member/scoped_spec.rb +3 -3
  139. data/spec/graphql/schema/printer_spec.rb +244 -96
  140. data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
  141. data/spec/graphql/schema/resolver_spec.rb +1 -1
  142. data/spec/graphql/schema/warden_spec.rb +35 -11
  143. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
  144. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  145. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  146. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  147. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  148. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  149. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  150. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -1
  151. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  152. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  153. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  154. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  155. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  156. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  157. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  158. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  159. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  160. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  161. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  162. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  163. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  164. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  165. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  166. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  167. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
  168. data/spec/graphql/static_validation/validator_spec.rb +6 -4
  169. data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
  170. data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
  171. data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
  172. data/spec/integration/mongoid/star_trek/schema.rb +5 -5
  173. data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
  174. data/spec/integration/rails/graphql/schema_spec.rb +2 -2
  175. data/spec/integration/rails/spec_helper.rb +10 -0
  176. data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
  177. data/spec/integration/tmp/dummy/Gemfile +45 -0
  178. data/spec/integration/tmp/dummy/README.rdoc +28 -0
  179. data/spec/integration/tmp/dummy/Rakefile +6 -0
  180. data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
  181. data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
  182. data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
  183. data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
  184. data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
  185. data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
  186. data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
  187. data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
  188. data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
  189. data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
  190. data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
  191. data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
  192. data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
  193. data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
  194. data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
  195. data/spec/integration/tmp/dummy/bin/bundle +3 -0
  196. data/spec/integration/tmp/dummy/bin/rails +4 -0
  197. data/spec/integration/tmp/dummy/bin/rake +4 -0
  198. data/spec/integration/tmp/dummy/bin/setup +29 -0
  199. data/spec/integration/tmp/dummy/config.ru +4 -0
  200. data/spec/integration/tmp/dummy/config/application.rb +32 -0
  201. data/spec/integration/tmp/dummy/config/boot.rb +3 -0
  202. data/spec/integration/tmp/dummy/config/environment.rb +5 -0
  203. data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
  204. data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
  205. data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
  206. data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
  207. data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
  208. data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
  209. data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  210. data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
  211. data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
  212. data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
  213. data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  214. data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
  215. data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
  216. data/spec/integration/tmp/dummy/config/routes.rb +61 -0
  217. data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
  218. data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
  219. data/spec/integration/tmp/dummy/public/404.html +67 -0
  220. data/spec/integration/tmp/dummy/public/422.html +67 -0
  221. data/spec/integration/tmp/dummy/public/500.html +66 -0
  222. data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
  223. data/spec/integration/tmp/dummy/public/robots.txt +5 -0
  224. data/spec/support/dummy/schema.rb +2 -2
  225. data/spec/support/error_bubbling_helpers.rb +23 -0
  226. data/spec/support/jazz.rb +53 -6
  227. data/spec/support/lazy_helpers.rb +26 -8
  228. data/spec/support/new_relic.rb +3 -0
  229. data/spec/support/skylight.rb +3 -0
  230. data/spec/support/star_wars/schema.rb +13 -9
  231. data/spec/support/static_validation_helpers.rb +3 -1
  232. metadata +145 -22
  233. data/lib/graphql/language/comments.rb +0 -45
  234. data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
  235. data/spec/integration/tmp/app/graphql/types/family_type.rb +0 -9
@@ -32,7 +32,12 @@ module GraphQL
32
32
  # Without the interpreter, the inputs are unwrapped by an instrumenter.
33
33
  # But when using the interpreter, no instrumenters are applied.
34
34
  if context.interpreter?
35
- input = inputs[:input]
35
+ input = inputs[:input].to_h
36
+ # Transfer these from the top-level hash to the
37
+ # shortcutted `input:` object
38
+ self.class.extras.each do |ext|
39
+ input[ext] = inputs[ext]
40
+ end
36
41
  else
37
42
  input = inputs
38
43
  end
@@ -310,7 +310,7 @@ module GraphQL
310
310
  type: type_expr,
311
311
  description: description,
312
312
  extras: extras,
313
- method: :resolve_with_support,
313
+ resolver_method: :resolve_with_support,
314
314
  resolver_class: self,
315
315
  arguments: arguments,
316
316
  null: null,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/static_validation/message"
2
+ require "graphql/static_validation/error"
3
3
  require "graphql/static_validation/definition_dependencies"
4
4
  require "graphql/static_validation/type_stack"
5
5
  require "graphql/static_validation/validator"
@@ -15,3 +15,4 @@ end
15
15
 
16
16
  require "graphql/static_validation/all_rules"
17
17
  require "graphql/static_validation/default_visitor"
18
+ require "graphql/static_validation/interpreter_visitor"
@@ -25,6 +25,7 @@ module GraphQL
25
25
  GraphQL::StaticValidation::ArgumentsAreDefined,
26
26
  GraphQL::StaticValidation::ArgumentLiteralsAreCompatible,
27
27
  GraphQL::StaticValidation::RequiredArgumentsArePresent,
28
+ GraphQL::StaticValidation::RequiredInputObjectAttributesArePresent,
28
29
  GraphQL::StaticValidation::ArgumentNamesAreUnique,
29
30
  GraphQL::StaticValidation::VariableNamesAreUnique,
30
31
  GraphQL::StaticValidation::VariablesAreInputTypes,
@@ -14,6 +14,11 @@ 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
+
17
22
  attr_reader :context
18
23
 
19
24
  # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
@@ -27,12 +32,22 @@ module GraphQL
27
32
  # Build a class to visit the AST and perform validation,
28
33
  # or use a pre-built class if rules is `ALL_RULES` or empty.
29
34
  # @param rules [Array<Module, Class>]
35
+ # @param rewrite [Boolean] if `false`, don't include rewrite
30
36
  # @return [Class] A class for validating `rules` during visitation
31
- def self.including_rules(rules)
37
+ def self.including_rules(rules, rewrite: true)
32
38
  if rules.none?
33
- NoValidateVisitor
39
+ if rewrite
40
+ NoValidateVisitor
41
+ else
42
+ # It's not doing _anything?!?_
43
+ BaseVisitor
44
+ end
34
45
  elsif rules == ALL_RULES
35
- DefaultVisitor
46
+ if rewrite
47
+ DefaultVisitor
48
+ else
49
+ InterpreterVisitor
50
+ end
36
51
  else
37
52
  visitor_class = Class.new(self) do
38
53
  include(GraphQL::StaticValidation::DefinitionDependencies)
@@ -45,7 +60,9 @@ module GraphQL
45
60
  end
46
61
  end
47
62
 
48
- visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
63
+ if rewrite
64
+ visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
65
+ end
49
66
  visitor_class.include(ContextMethods)
50
67
  visitor_class
51
68
  end
@@ -172,13 +189,11 @@ module GraphQL
172
189
 
173
190
  private
174
191
 
175
- # Error `message` is located at `node`
176
- def add_error(message, nodes, path: nil)
177
- path ||= @path.dup
178
- nodes = Array(nodes)
179
- m = GraphQL::StaticValidation::Message.new(message, nodes: nodes, path: path)
180
- context.errors << m
192
+ def add_error(error, path: nil)
193
+ error.path ||= (path || @path.dup)
194
+ context.errors << error
181
195
  end
196
+
182
197
  end
183
198
  end
184
199
  end
@@ -20,7 +20,7 @@ module GraphQL
20
20
 
21
21
  # First-level usages of spreads within definitions
22
22
  # (When a key has an empty list as its value,
23
- # we can resolve that key's depenedents)
23
+ # we can resolve that key's dependents)
24
24
  # { definition_node => [node, node ...] }
25
25
  @defdep_immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
26
26
 
@@ -72,7 +72,7 @@ module GraphQL
72
72
 
73
73
 
74
74
  # Map definition AST nodes to the definition AST nodes they depend on.
75
- # Expose circular depednencies.
75
+ # Expose circular dependencies.
76
76
  class DependencyMap
77
77
  # @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
78
78
  attr_reader :cyclical_definitions
@@ -143,7 +143,7 @@ module GraphQL
143
143
  # Register the dependency AND second-order dependencies
144
144
  dependency_map[definition_node] << fragment_node
145
145
  dependency_map[definition_node].concat(dependency_map[fragment_node])
146
- # Since we've regestered it, remove it from our to-do list
146
+ # Since we've registered it, remove it from our to-do list
147
147
  deps = @defdep_immediate_dependencies[definition_node]
148
148
  # Can't find a way to _just_ delete from `deps` and return the deleted entries
149
149
  removed, remaining = deps.partition { |spread| spread.name == fragment_node.name }
@@ -2,22 +2,23 @@
2
2
  module GraphQL
3
3
  module StaticValidation
4
4
  # Generates GraphQL-compliant validation message.
5
- class Message
5
+ class Error
6
6
  # Convenience for validators
7
- module MessageHelper
8
- # Error `message` is located at `node`
9
- def message(message, nodes, context: nil, path: nil)
7
+ module ErrorHelper
8
+ # Error `error_message` is located at `node`
9
+ def error(error_message, nodes, context: nil, path: nil, extensions: {})
10
10
  path ||= context.path
11
11
  nodes = Array(nodes)
12
- GraphQL::StaticValidation::Message.new(message, nodes: nodes, path: path)
12
+ GraphQL::StaticValidation::Error.new(error_message, nodes: nodes, path: path)
13
13
  end
14
14
  end
15
15
 
16
- attr_reader :message, :path
16
+ attr_reader :message
17
+ attr_accessor :path
17
18
 
18
- def initialize(message, path: [], nodes: [])
19
+ def initialize(message, path: nil, nodes: [])
19
20
  @message = message
20
- @nodes = nodes
21
+ @nodes = Array(nodes)
21
22
  @path = path
22
23
  end
23
24
 
@@ -25,9 +26,8 @@ module GraphQL
25
26
  def to_h
26
27
  {
27
28
  "message" => message,
28
- "locations" => locations,
29
- "fields" => path,
30
- }
29
+ "locations" => locations
30
+ }.tap { |h| h["path"] = path unless path.nil? }
31
31
  end
32
32
 
33
33
  private
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class InterpreterVisitor < BaseVisitor
5
+ include(GraphQL::StaticValidation::DefinitionDependencies)
6
+
7
+ StaticValidation::ALL_RULES.reverse_each do |r|
8
+ include(r)
9
+ end
10
+
11
+ include(ContextMethods)
12
+ end
13
+ end
14
+ end
@@ -9,29 +9,61 @@ module GraphQL
9
9
  end
10
10
 
11
11
  def validate(ast_value, type)
12
- if ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
13
- !type.kind.non_null?
12
+ if type.nil?
13
+ # this means we're an undefined argument, see #present_input_field_values_are_valid
14
+ return maybe_raise_if_invalid(ast_value) do
15
+ false
16
+ end
17
+ elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
18
+ maybe_raise_if_invalid(ast_value) do
19
+ !type.kind.non_null?
20
+ end
14
21
  elsif type.kind.non_null?
15
- (!ast_value.nil?) && validate(ast_value, type.of_type)
22
+ maybe_raise_if_invalid(ast_value) do
23
+ (!ast_value.nil?)
24
+ end && validate(ast_value, type.of_type)
16
25
  elsif type.kind.list?
17
26
  item_type = type.of_type
18
27
  ensure_array(ast_value).all? { |val| validate(val, item_type) }
19
28
  elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
20
29
  true
21
30
  elsif type.kind.scalar? && constant_scalar?(ast_value)
22
- type.valid_input?(ast_value, @context)
23
- elsif type.kind.enum? && ast_value.is_a?(GraphQL::Language::Nodes::Enum)
24
- type.valid_input?(ast_value.name, @context)
31
+ maybe_raise_if_invalid(ast_value) do
32
+ type.valid_input?(ast_value, @context)
33
+ end
34
+ elsif type.kind.enum?
35
+ maybe_raise_if_invalid(ast_value) do
36
+ if ast_value.is_a?(GraphQL::Language::Nodes::Enum)
37
+ type.valid_input?(ast_value.name, @context)
38
+ else
39
+ # if our ast_value isn't an Enum it's going to be invalid so return false
40
+ false
41
+ end
42
+ end
25
43
  elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
26
- required_input_fields_are_present(type, ast_value) &&
27
- present_input_field_values_are_valid(type, ast_value)
44
+ maybe_raise_if_invalid(ast_value) do
45
+ required_input_fields_are_present(type, ast_value) && present_input_field_values_are_valid(type, ast_value)
46
+ end
28
47
  else
29
- false
48
+ maybe_raise_if_invalid(ast_value) do
49
+ false
50
+ end
30
51
  end
31
52
  end
32
53
 
33
54
  private
34
55
 
56
+ def maybe_raise_if_invalid(ast_value)
57
+ ret = yield
58
+ if !@context.schema.error_bubbling && !ret
59
+ e = LiteralValidationError.new
60
+ e.ast_value = ast_value
61
+ raise e
62
+ else
63
+ ret
64
+ end
65
+ end
66
+
35
67
  # The GraphQL grammar supports variables embedded within scalars but graphql.js
36
68
  # doesn't support it so we won't either for simplicity
37
69
  def constant_scalar?(ast_value)
@@ -47,19 +79,30 @@ module GraphQL
47
79
  end
48
80
 
49
81
  def required_input_fields_are_present(type, ast_node)
82
+ # TODO - would be nice to use these to create an error message so the caller knows
83
+ # that required fields are missing
50
84
  required_field_names = @warden.arguments(type)
51
85
  .select { |f| f.type.kind.non_null? }
52
86
  .map(&:name)
53
87
  present_field_names = ast_node.arguments.map(&:name)
54
88
  missing_required_field_names = required_field_names - present_field_names
55
- missing_required_field_names.none?
89
+ if @context.schema.error_bubbling
90
+ missing_required_field_names.none?
91
+ else
92
+ missing_required_field_names.all? do |name|
93
+ validate(GraphQL::Language::Nodes::NullValue.new(name: name), @warden.arguments(type).find { |f| f.name == name }.type )
94
+ end
95
+ end
56
96
  end
57
97
 
58
98
  def present_input_field_values_are_valid(type, ast_node)
59
99
  field_map = @warden.arguments(type).reduce({}) { |m, f| m[f.name] = f; m}
60
100
  ast_node.arguments.all? do |value|
61
101
  field = field_map[value.name]
62
- field && validate(value.value, field.type)
102
+ # we want to call validate on an argument even if it's an invalid one
103
+ # so that our raise exception is on it instead of the entire InputObject
104
+ type = field && field.type
105
+ validate(value.value, type)
63
106
  end
64
107
  end
65
108
 
@@ -31,17 +31,46 @@ module GraphQL
31
31
  begin
32
32
  valid = context.valid_literal?(node.value, arg_defn.type)
33
33
  rescue GraphQL::CoercionError => err
34
- error_message = err.message
34
+ context.schema.error_bubbling
35
+ if !context.schema.error_bubbling && !arg_defn.type.unwrap.kind.scalar?
36
+ # if error bubbling is disabled and the arg that caused this error isn't a scalar then
37
+ # short-circuit here so we avoid bubbling this up to whatever input_object / array contains us
38
+ return super
39
+ end
40
+ error = GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(err.message, nodes: parent, type: "CoercionError")
41
+ rescue GraphQL::LiteralValidationError => err
42
+ # check to see if the ast node that caused the error to be raised is
43
+ # the same as the node we were checking here.
44
+ matched = if arg_defn.type.kind.list?
45
+ # for a list we claim an error if the node is contained in our list
46
+ node.value.include?(err.ast_value)
47
+ elsif arg_defn.type.kind.input_object? && node.value.is_a?(GraphQL::Language::Nodes::InputObject)
48
+ # for an input object we check the arguments
49
+ node.value.arguments.include?(err.ast_value)
50
+ else
51
+ # otherwise we just check equality
52
+ node.value == (err.ast_value)
53
+ end
54
+ if !matched
55
+ # This node isn't the node that caused the error,
56
+ # So halt this visit but continue visiting the rest of the tree
57
+ return super
58
+ end
35
59
  end
36
60
 
37
61
  if !valid
38
- error_message ||= begin
62
+ error ||= begin
39
63
  kind_of_node = node_type(parent)
40
64
  error_arg_name = parent_name(parent, parent_defn)
41
- "Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'."
42
- end
43
65
 
44
- add_error(error_message, parent)
66
+ GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(
67
+ "Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'.",
68
+ nodes: parent,
69
+ type: kind_of_node,
70
+ argument: node.name
71
+ )
72
+ end
73
+ add_error(error)
45
74
  end
46
75
  end
47
76
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class ArgumentLiteralsAreCompatibleError < StaticValidation::Error
5
+ attr_reader :type_name
6
+ attr_reader :argument_name
7
+
8
+ def initialize(message, path: nil, nodes: [], type:, argument: nil)
9
+ super(message, path: path, nodes: nodes)
10
+ @type_name = type
11
+ @argument_name = argument
12
+ end
13
+
14
+ # A hash representation of this Message
15
+ def to_h
16
+ extensions = {
17
+ "code" => code,
18
+ "typeName" => type_name
19
+ }.tap { |h| h["argumentName"] = argument_name unless argument_name.nil? }
20
+
21
+ super.merge({
22
+ "extensions" => extensions
23
+ })
24
+ end
25
+
26
+ def code
27
+ "argumentLiteralsIncompatible"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,7 +2,7 @@
2
2
  module GraphQL
3
3
  module StaticValidation
4
4
  module ArgumentNamesAreUnique
5
- include GraphQL::StaticValidation::Message::MessageHelper
5
+ include GraphQL::StaticValidation::Error::ErrorHelper
6
6
 
7
7
  def on_field(node, parent)
8
8
  validate_arguments(node)
@@ -21,7 +21,7 @@ module GraphQL
21
21
  argument_defns.each { |a| args_by_name[a.name] << a }
22
22
  args_by_name.each do |name, defns|
23
23
  if defns.size > 1
24
- add_error("There can be only one argument named \"#{name}\"", defns)
24
+ add_error(GraphQL::StaticValidation::ArgumentNamesAreUniqueError.new("There can be only one argument named \"#{name}\"", nodes: defns, name: name))
25
25
  end
26
26
  end
27
27
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class ArgumentNamesAreUniqueError < StaticValidation::Error
5
+ attr_reader :name
6
+
7
+ def initialize(message, path: nil, nodes: [], name:)
8
+ super(message, path: path, nodes: nodes)
9
+ @name = name
10
+ end
11
+
12
+ # A hash representation of this Message
13
+ def to_h
14
+ extensions = {
15
+ "code" => code,
16
+ "name" => name
17
+ }
18
+
19
+ super.merge({
20
+ "extensions" => extensions
21
+ })
22
+ end
23
+
24
+ def code
25
+ "argumentNotUnique"
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -29,7 +29,13 @@ module GraphQL
29
29
  elsif parent_defn
30
30
  kind_of_node = node_type(parent)
31
31
  error_arg_name = parent_name(parent, parent_defn)
32
- add_error("#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'", node)
32
+ add_error(GraphQL::StaticValidation::ArgumentsAreDefinedError.new(
33
+ "#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'",
34
+ nodes: node,
35
+ name: error_arg_name,
36
+ type: kind_of_node,
37
+ argument: node.name
38
+ ))
33
39
  else
34
40
  # Some other weird error
35
41
  super