graphql 1.9.0.pre1 → 1.9.0.pre2

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.
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