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
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class RequiredInputObjectAttributesArePresentError < StaticValidation::Error
5
+ attr_reader :argument_type
6
+ attr_reader :argument_name
7
+ attr_reader :input_object_type
8
+
9
+ def initialize(message, path:, nodes:, argument_type:, argument_name:, input_object_type:)
10
+ super(message, path: path, nodes: nodes)
11
+ @argument_type = argument_type
12
+ @argument_name = argument_name
13
+ @input_object_type = input_object_type
14
+ end
15
+
16
+ # A hash representation of this Message
17
+ def to_h
18
+ extensions = {
19
+ "code" => code,
20
+ "argumentName" => argument_name,
21
+ "argumentType" => argument_type,
22
+ "inputObjectType" => input_object_type,
23
+ }
24
+
25
+ super.merge({
26
+ "extensions" => extensions
27
+ })
28
+ end
29
+
30
+ def code
31
+ "missingRequiredInputObjectAttribute"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,7 +4,10 @@ module GraphQL
4
4
  module SubscriptionRootExists
5
5
  def on_operation_definition(node, _parent)
6
6
  if node.operation_type == "subscription" && context.warden.root_type_for_operation("subscription").nil?
7
- add_error('Schema is not configured for subscriptions', node)
7
+ add_error(GraphQL::StaticValidation::SubscriptionRootExistsError.new(
8
+ 'Schema is not configured for subscriptions',
9
+ nodes: node
10
+ ))
8
11
  else
9
12
  super
10
13
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class SubscriptionRootExistsError < StaticValidation::Error
5
+
6
+ def initialize(message, path: nil, nodes: [])
7
+ super(message, path: path, nodes: nodes)
8
+ end
9
+
10
+ # A hash representation of this Message
11
+ def to_h
12
+ extensions = {
13
+ "code" => code,
14
+ }
15
+
16
+ super.merge({
17
+ "extensions" => extensions
18
+ })
19
+ end
20
+
21
+ def code
22
+ "missingSubscriptionConfiguration"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -35,10 +35,11 @@ module GraphQL
35
35
  node.directives.each do |ast_directive|
36
36
  directive_name = ast_directive.name
37
37
  if used_directives[directive_name]
38
- add_error(
38
+ add_error(GraphQL::StaticValidation::UniqueDirectivesPerLocationError.new(
39
39
  "The directive \"#{directive_name}\" can only be used once at this location.",
40
- [used_directives[directive_name], ast_directive]
41
- )
40
+ nodes: [used_directives[directive_name], ast_directive],
41
+ directive: directive_name,
42
+ ))
42
43
  else
43
44
  used_directives[directive_name] = ast_directive
44
45
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class UniqueDirectivesPerLocationError < StaticValidation::Error
5
+ attr_reader :directive_name
6
+
7
+ def initialize(message, path: nil, nodes: [], directive:)
8
+ super(message, path: path, nodes: nodes)
9
+ @directive_name = directive
10
+ end
11
+
12
+ # A hash representation of this Message
13
+ def to_h
14
+ extensions = {
15
+ "code" => code,
16
+ "directiveName" => directive_name
17
+ }
18
+
19
+ super.merge({
20
+ "extensions" => extensions
21
+ })
22
+ end
23
+
24
+ def code
25
+ "directiveNotUniqueForLocation"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,7 +6,12 @@ module GraphQL
6
6
  if !node.default_value.nil?
7
7
  value = node.default_value
8
8
  if node.type.is_a?(GraphQL::Language::Nodes::NonNullType)
9
- add_error("Non-null variable $#{node.name} can't have a default value", node)
9
+ add_error(GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTypedError.new(
10
+ "Non-null variable $#{node.name} can't have a default value",
11
+ nodes: node,
12
+ name: node.name,
13
+ error_type: VariableDefaultValuesAreCorrectlyTypedError::VIOLATIONS[:INVALID_ON_NON_NULL]
14
+ ))
10
15
  else
11
16
  type = context.schema.type_from_ast(node.type)
12
17
  if type.nil?
@@ -16,18 +21,27 @@ module GraphQL
16
21
  valid = context.valid_literal?(value, type)
17
22
  rescue GraphQL::CoercionError => err
18
23
  error_message = err.message
24
+ rescue GraphQL::LiteralValidationError
25
+ # noop, we just want to stop any LiteralValidationError from propagating
19
26
  end
20
27
 
21
28
  if !valid
22
29
  error_message ||= "Default value for $#{node.name} doesn't match type #{type}"
23
- add_error(error_message, node)
30
+ VariableDefaultValuesAreCorrectlyTypedError
31
+ add_error(GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTypedError.new(
32
+ error_message,
33
+ nodes: node,
34
+ name: node.name,
35
+ type: type.to_s,
36
+ error_type: VariableDefaultValuesAreCorrectlyTypedError::VIOLATIONS[:INVALID_TYPE]
37
+ ))
24
38
  end
25
- end
26
- end
39
+ end
40
+ end
27
41
  end
28
-
42
+
29
43
  super
30
44
  end
31
45
  end
32
- end
46
+ end
33
47
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class VariableDefaultValuesAreCorrectlyTypedError < StaticValidation::Error
5
+ attr_reader :variable_name
6
+ attr_reader :type_name
7
+ attr_reader :violation
8
+
9
+ VIOLATIONS = {
10
+ :INVALID_TYPE => "defaultValueInvalidType",
11
+ :INVALID_ON_NON_NULL => "defaultValueInvalidOnNonNullVariable",
12
+ }
13
+
14
+ def initialize(message, path: nil, nodes: [], name:, type: nil, error_type:)
15
+ super(message, path: path, nodes: nodes)
16
+ @variable_name = name
17
+ @type_name = type
18
+ raise("Unexpected error type: #{error_type}") if !VIOLATIONS.values.include?(error_type)
19
+ @violation = error_type
20
+ end
21
+
22
+ # A hash representation of this Message
23
+ def to_h
24
+ extensions = {
25
+ "code" => code,
26
+ "variableName" => variable_name
27
+ }.tap { |h| h["typeName"] = type_name unless type_name.nil? }
28
+
29
+ super.merge({
30
+ "extensions" => extensions
31
+ })
32
+ end
33
+
34
+ def code
35
+ @violation
36
+ end
37
+ end
38
+ end
39
+ end
@@ -9,7 +9,11 @@ module GraphQL
9
9
  var_defns.each { |v| vars_by_name[v.name] << v }
10
10
  vars_by_name.each do |name, defns|
11
11
  if defns.size > 1
12
- add_error("There can only be one variable named \"#{name}\"", defns)
12
+ add_error(GraphQL::StaticValidation::VariableNamesAreUniqueError.new(
13
+ "There can only be one variable named \"#{name}\"",
14
+ nodes: defns,
15
+ name: name
16
+ ))
13
17
  end
14
18
  end
15
19
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class VariableNamesAreUniqueError < StaticValidation::Error
5
+ attr_reader :variable_name
6
+
7
+ def initialize(message, path: nil, nodes: [], name:)
8
+ super(message, path: path, nodes: nodes)
9
+ @variable_name = name
10
+ end
11
+
12
+ # A hash representation of this Message
13
+ def to_h
14
+ extensions = {
15
+ "code" => code,
16
+ "variableName" => variable_name
17
+ }
18
+
19
+ super.merge({
20
+ "extensions" => extensions
21
+ })
22
+ end
23
+
24
+ def code
25
+ "variableNotUnique"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -84,7 +84,14 @@ module GraphQL
84
84
  end
85
85
 
86
86
  def create_error(error_message, var_type, ast_var, arg_defn, arg_node)
87
- add_error("#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})", arg_node)
87
+ add_error(GraphQL::StaticValidation::VariableUsagesAreAllowedError.new(
88
+ "#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})",
89
+ nodes: arg_node,
90
+ name: ast_var.name,
91
+ type: var_type.to_s,
92
+ argument: arg_node.name,
93
+ error: error_message
94
+ ))
88
95
  end
89
96
 
90
97
  def wrap_var_type_with_depth_of_arg(var_type, arg_node)
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class VariableUsagesAreAllowedError < StaticValidation::Error
5
+ attr_reader :type_name
6
+ attr_reader :variable_name
7
+ attr_reader :argument_name
8
+ attr_reader :error_message
9
+
10
+ def initialize(message, path: nil, nodes: [], type:, name:, argument:, error:)
11
+ super(message, path: path, nodes: nodes)
12
+ @type_name = type
13
+ @variable_name = name
14
+ @argument_name = argument
15
+ @error_message = error
16
+ end
17
+
18
+ # A hash representation of this Message
19
+ def to_h
20
+ extensions = {
21
+ "code" => code,
22
+ "variableName" => variable_name,
23
+ "typeName" => type_name,
24
+ "argumentName" => argument_name,
25
+ "errorMessage" => error_message
26
+ }
27
+
28
+ super.merge({
29
+ "extensions" => extensions
30
+ })
31
+ end
32
+
33
+ def code
34
+ "variableMismatch"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -7,9 +7,19 @@ module GraphQL
7
7
  type = context.warden.get_type(type_name)
8
8
 
9
9
  if type.nil?
10
- add_error("#{type_name} isn't a defined input type (on $#{node.name})", node)
10
+ add_error(GraphQL::StaticValidation::VariablesAreInputTypesError.new(
11
+ "#{type_name} isn't a defined input type (on $#{node.name})",
12
+ nodes: node,
13
+ name: node.name,
14
+ type: type_name
15
+ ))
11
16
  elsif !type.kind.input?
12
- add_error("#{type.name} isn't a valid input type (on $#{node.name})", node)
17
+ add_error(GraphQL::StaticValidation::VariablesAreInputTypesError.new(
18
+ "#{type.name} isn't a valid input type (on $#{node.name})",
19
+ nodes: node,
20
+ name: node.name,
21
+ type: type_name
22
+ ))
13
23
  end
14
24
 
15
25
  super
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class VariablesAreInputTypesError < StaticValidation::Error
5
+ attr_reader :type_name
6
+ attr_reader :variable_name
7
+
8
+ def initialize(message, path: nil, nodes: [], type:, name:)
9
+ super(message, path: path, nodes: nodes)
10
+ @type_name = type
11
+ @variable_name = name
12
+ end
13
+
14
+ # A hash representation of this Message
15
+ def to_h
16
+ extensions = {
17
+ "code" => code,
18
+ "typeName" => type_name,
19
+ "variableName" => variable_name
20
+ }
21
+
22
+ super.merge({
23
+ "extensions" => extensions
24
+ })
25
+ end
26
+
27
+ def code
28
+ "variableRequiresValidType"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -125,12 +125,28 @@ module GraphQL
125
125
  # Declared but not used:
126
126
  node_variables
127
127
  .select { |name, usage| usage.declared? && !usage.used? }
128
- .each { |var_name, usage| add_error("Variable $#{var_name} is declared by #{usage.declared_by.name} but not used", usage.declared_by, path: usage.path) }
128
+ .each { |var_name, usage|
129
+ add_error(GraphQL::StaticValidation::VariablesAreUsedAndDefinedError.new(
130
+ "Variable $#{var_name} is declared by #{usage.declared_by.name} but not used",
131
+ nodes: usage.declared_by,
132
+ path: usage.path,
133
+ name: var_name,
134
+ error_type: VariablesAreUsedAndDefinedError::VIOLATIONS[:VARIABLE_NOT_USED]
135
+ ))
136
+ }
129
137
 
130
138
  # Used but not declared:
131
139
  node_variables
132
140
  .select { |name, usage| usage.used? && !usage.declared? }
133
- .each { |var_name, usage| add_error("Variable $#{var_name} is used by #{usage.used_by.name} but not declared", usage.ast_node, path: usage.path) }
141
+ .each { |var_name, usage|
142
+ add_error(GraphQL::StaticValidation::VariablesAreUsedAndDefinedError.new(
143
+ "Variable $#{var_name} is used by #{usage.used_by.name} but not declared",
144
+ nodes: usage.ast_node,
145
+ path: usage.path,
146
+ name: var_name,
147
+ error_type: VariablesAreUsedAndDefinedError::VIOLATIONS[:VARIABLE_NOT_DEFINED]
148
+ ))
149
+ }
134
150
  end
135
151
  end
136
152
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class VariablesAreUsedAndDefinedError < StaticValidation::Error
5
+ attr_reader :variable_name
6
+ attr_reader :violation
7
+
8
+ VIOLATIONS = {
9
+ :VARIABLE_NOT_USED => "variableNotUsed",
10
+ :VARIABLE_NOT_DEFINED => "variableNotDefined",
11
+ }
12
+
13
+ def initialize(message, path: nil, nodes: [], name:, error_type:)
14
+ super(message, path: path, nodes: nodes)
15
+ @variable_name = name
16
+ raise("Unexpected error type: #{error_type}") if !VIOLATIONS.values.include?(error_type)
17
+ @violation = error_type
18
+ end
19
+
20
+ # A hash representation of this Message
21
+ def to_h
22
+ extensions = {
23
+ "code" => code,
24
+ "variableName" => variable_name
25
+ }
26
+
27
+ super.merge({
28
+ "extensions" => extensions
29
+ })
30
+ end
31
+
32
+ def code
33
+ @violation
34
+ end
35
+ end
36
+ end
37
+ end
@@ -23,27 +23,37 @@ module GraphQL
23
23
  # @return [Array<Hash>]
24
24
  def validate(query, validate: true)
25
25
  query.trace("validate", { validate: validate, query: query }) do
26
+ can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis?
27
+ errors = if validate == false && can_skip_rewrite
28
+ []
29
+ else
30
+ rules_to_use = validate ? @rules : []
31
+ visitor_class = BaseVisitor.including_rules(rules_to_use, rewrite: !can_skip_rewrite)
26
32
 
27
- rules_to_use = validate ? @rules : []
28
- visitor_class = BaseVisitor.including_rules(rules_to_use)
33
+ context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)
29
34
 
30
- context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)
31
-
32
- # Attach legacy-style rules
33
- rules_to_use.each do |rule_class_or_module|
34
- if rule_class_or_module.method_defined?(:validate)
35
- rule_class_or_module.new.validate(context)
35
+ # Attach legacy-style rules
36
+ rules_to_use.each do |rule_class_or_module|
37
+ if rule_class_or_module.method_defined?(:validate)
38
+ rule_class_or_module.new.validate(context)
39
+ end
36
40
  end
41
+
42
+ context.visitor.visit
43
+ context.errors
37
44
  end
38
45
 
39
- context.visitor.visit
40
- # Post-validation: allow validators to register handlers on rewritten query nodes
41
- rewrite_result = context.visitor.rewrite_document
46
+
47
+ irep = if errors.none? && context
48
+ # Only return this if there are no errors and validation was actually run
49
+ context.visitor.rewrite_document
50
+ else
51
+ nil
52
+ end
42
53
 
43
54
  {
44
- errors: context.errors,
45
- # If there were errors, the irep is garbage
46
- irep: context.errors.any? ? nil : rewrite_result,
55
+ errors: errors,
56
+ irep: irep,
47
57
  }
48
58
  end
49
59
  end